class Interface(genie.libs.conf.interface.Interface): """ base Interface class for IOS-XE devices """ def __new__(cls, *args, **kwargs): factory_cls = cls if cls is Interface: try: name = kwargs['name'] except KeyError: raise TypeError('\'name\' argument missing') d_parsed = genie.libs.conf.interface.ParsedInterfaceName( name, kwargs.get('device', None)) if d_parsed.subintf: factory_cls = SubInterface else: try: factory_cls = cls._name_to_class_map[d_parsed.type] except KeyError: pass if factory_cls is not cls: self = factory_cls.__new__(factory_cls, *args, **kwargs) elif super().__new__ is object.__new__: self = super().__new__(factory_cls) else: self = super().__new__(factory_cls, *args, **kwargs) return self switchport = managedattribute( name='switchport', default=None, type=(None, managedattribute.test_istype(bool)), doc='Configure switchport') sw_trunk_allowed_vlan = managedattribute( name='sw_trunk_allowed_vlan', default=None, type=(None, managedattribute.test_istype(str)), doc= 'Allowed Vlan on the trunk') sw_access_allowed_vlan = managedattribute( name='sw_access_allowed_vlan', default=None, type=(None, managedattribute.test_istype(str)), doc= 'Access VLAN assigned to the interfaces') sw_trunk_native_vlan = managedattribute( name='sw_trunk_native_vlan', default=None, type=(None, managedattribute.test_istype(str)), doc= 'Set the native VLAN id for untagged frames arriving on\ a trunk interface') vrf_downstream = managedattribute( name='vrf_downstream ', default=None, type=(None, managedattribute.test_istype(str)), doc= 'vrf_downstream ') class ENCAPSULATION(Enum): dot1q = 'dot1q' encapsulation = managedattribute( name='encapsulation ', default=None, type=(None, ENCAPSULATION), doc= 'encapsulation ') ipv6_autoconf_default = managedattribute( name='ipv6_autoconf_default', default=None, type=(None, managedattribute.test_istype(bool)), doc= 'ipv6_autoconf_default') def build_config(self, apply=True, attributes=None, unconfig=False, **kwargs): assert not kwargs attributes = AttributesHelper(self, attributes) configurations = CliConfigBuilder(unconfig=unconfig) with self._build_config_create_interface_submode_context(configurations): self._build_config_interface_submode(configurations=configurations, attributes=attributes, unconfig=unconfig) if apply: if configurations: self.device.configure(configurations, fail_invalid=True) else: return CliConfig(device=self.device, unconfig=unconfig, cli_config=configurations) def build_unconfig(self, apply=True, attributes=None, **kwargs): return self.build_config(apply=apply, attributes=attributes, unconfig=True, **kwargs) def _build_config_create_interface_submode_context(self, configurations): return configurations.submode_context('interface {}'.format(self.name)) def _build_config_interface_submode(self, configurations, attributes, unconfig): # iosxe: interface {name} / vrf forwarding someword if attributes.value('vrf_downstream'): configurations.append_line( attributes.format('vrf forwarding {vrf.name}' ' downstream {vrf_downstream}')) else: configurations.append_line( attributes.format('vrf forwarding {vrf.name}')) # iosxe: interface {name} / description some line data v = attributes.value('description') if v: if v is True: pass # TODO Create a usefull default description configurations.append_line('description {}'.format(v)) # iosxe: interface {name} / bandwidth <0-4294967295> configurations.append_line(attributes.format('bandwidth {bandwidth}')) # iosxe: interface {name} / ip address 1.1.1.1 255.255.255.255 configurations.append_line( attributes.format('ip address {ipv4.ip} {ipv4.netmask}')) # iosxe: interface {name} / ipv6 address 2001::1/128 configurations.append_line( attributes.format('ipv6 address {ipv6.with_prefixlen}')) # iosxe: interface {name} / mtu 64 configurations.append_line( attributes.format('mtu {mtu}')) # iosxe: interface {name} / shutdown # enabled enabled = attributes.value('enabled') if enabled is not None: if enabled: config_cmd = 'no shutdown' unconfig_cmd = 'shutdown' else: config_cmd = 'shutdown' unconfig_cmd = 'no shutdown' configurations.append_line( attributes.format(config_cmd), unconfig_cmd=unconfig_cmd) # Compatibility else: shutdown = attributes.value('shutdown') if shutdown is not None: if unconfig: # Special case: unconfiguring always applies shutdown configurations.append_line('shutdown', raw=True) elif shutdown: configurations.append_line('shutdown', raw=True) else: configurations.append_line('no shutdown', raw=True) # snmp trap link-status if attributes.value('link_up_down_trap_enable'): configurations.append_line( 'snmp trap link-status') # logging event link-status if attributes.value('link_status'): configurations.append_line( 'logging event link-status') # load-interval <load_interval> if attributes.value('load_interval'): configurations.append_line( attributes.format('load-interval {load_interval}')) # encapsulation <encapsulation> <first_dot1q> # encapsulation <encapsulation> <first_dot1q> native # encapsulation <encapsulation> <first_dot1q> second-dot1q <second_dot1q> if attributes.value('encapsulation') and \ attributes.value('first_dot1q'): if attributes.value('second_dot1q'): configurations.append_line( attributes.format('encapsulation {encapsulation.value} {first_dot1q}' ' second-dot1q {second_dot1q}'), unconfig_cmd='no encapsulation {}' .format(attributes.value('encapsulation').value)) elif attributes.value('native_vlan_dot1q'): configurations.append_line( attributes.format('encapsulation {encapsulation.value} {first_dot1q}' ' native'), unconfig_cmd='no encapsulation {}' .format(attributes.value('encapsulation').value)) else: configurations.append_line( attributes.format('encapsulation {encapsulation.value} {first_dot1q}'), unconfig_cmd='no encapsulation {}' .format(attributes.value('encapsulation').value)) # ipv6 enable if attributes.value('ipv6_enabled'): configurations.append_line('ipv6 enable') # ipv6 address autoconfig [default] if attributes.value('ipv6_autoconf'): if attributes.value('ipv6_autoconf_default'): configurations.append_line('ipv6 address autoconfig default') else: configurations.append_line('ipv6 address autoconfig') # ip unnumbered <unnumbered_intf_ref> configurations.append_line( attributes.format('ip unnumbered {unnumbered_intf_ref}'), unconfig_cmd='no ip unnumbered') # ipv6 unnumbered <ipv6_unnumbered_intf_ref> configurations.append_line( attributes.format('ipv6 unnumbered {ipv6_unnumbered_intf_ref}'), unconfig_cmd='no ipv6 unnumbered') # speed <port_speed> if attributes.value('port_speed'): configurations.append_line( attributes.format('speed {port_speed.value}')) # negotiation auto if attributes.value('auto_negotiate'): configurations.append_line('negotiation auto') # duplex <duplex_mode> if attributes.value('duplex_mode'): configurations.append_line( attributes.format('duplex {duplex_mode.value}')) # flowcontrol receive on|off if attributes.value('flow_control_receive'): configurations.append_line('flowcontrol receive on') elif attributes.value('flow_control_receive') == False: configurations.append_line('flowcontrol receive off') # flowcontrol send on|off if attributes.value('flow_control_send'): configurations.append_line('flowcontrol send on') elif attributes.value('flow_control_send') == False: configurations.append_line('flowcontrol send off') # ip address dhcp # ip address dhcp client-id <dhcp_client_id> # ip address dhcp client-id <dhcp_client_id> hostname <dhcp_hostname> if attributes.value('dhcp'): cfg_str = 'ip address dhcp' if attributes.value('dhcp_client_id'): cfg_str += ' client-id {dhcp_client_id}' if attributes.value('dhcp_hostname'): cfg_str += ' hostname {dhcp_hostname}' configurations.append_line( attributes.format(cfg_str)) # medium <medium > if attributes.value('medium'): configurations.append_line( attributes.format('medium {medium.value}')) # delay <delay > if attributes.value('delay'): configurations.append_line( attributes.format('delay {delay}')) # ----- switchport configure ---------# # iosxe: interface {name} / switchport # Switchport mode configuration can't be applied # on loopback and Vlan interfaces attribute definition if not re.match('[V|v]lan', self.name) and \ not re.match('[L|l]oopback', self.name): switchport = attributes.value('switchport') switchport_enable = attributes.value('switchport_enable') if switchport != None or switchport_enable != None: if switchport or switchport_enable: configurations.append_line( attributes.format('switchport')) else: configurations.append_line( attributes.format('no switchport'), unconfig_cmd='switchport') # location might be reconsidered # iosxe: interface {name} / switchport mode trunk switchport = attributes.value('switchport_mode') # if 'trunk' in str(switchport): configurations.append_line( attributes.format('switchport mode {switchport_mode.value}')) # iosxe: interface {name} / switchport trunk allowed vlan 100-110 configurations.append_line( attributes.format( 'switchport trunk allowed vlan {sw_trunk_allowed_vlan}')) configurations.append_line( attributes.format( 'switchport trunk allowed vlan {trunk_vlans}')) # iosxe: interface {name} / switchport trunk native vlan 100 configurations.append_line( attributes.format( 'switchport trunk native vlan {sw_trunk_native_vlan}')) configurations.append_line( attributes.format( 'switchport trunk native vlan {native_vlan}')) # iosxe: interface {name} / switchport access vlan 100 if 'access' in str(switchport): configurations.append_line( attributes.format('switchport access vlan {sw_access_allowed_vlan}')) configurations.append_line( attributes.format('switchport access vlan {access_vlan}')) # switchport trunk allowed vlan add <trunk_add_vlans> configurations.append_line( attributes.format('switchport trunk allowed vlan add {trunk_add_vlans}')) # switchport trunk allowed vlan remove <trunk_remove_vlans> configurations.append_line( attributes.format('switchport trunk allowed vlan remove {trunk_remove_vlans}')) # iosxr: interface {name} / vlan <vlan-id> ns, attributes2 = attributes.namespace('vlan') if ns is not None: configurations.append_block( ns.build_config(apply=False, attributes=attributes2, unconfig=unconfig)) # IPv4Addr attributes for ipv4addr, attributes2 in attributes.sequence_values( 'ipv4addr', sort=True): if unconfig: configurations.append_block(ipv4addr.build_unconfig( apply=False, attributes=attributes2)) else: configurations.append_block(ipv4addr.build_config( apply=False, attributes=attributes2)) # IPv6Addr attributes for ipv6addr, attributes2 in attributes.sequence_values( 'ipv6addr', sort=True): if unconfig: configurations.append_block(ipv6addr.build_unconfig( apply=False, attributes=attributes2)) else: configurations.append_block(ipv6addr.build_config( apply=False, attributes=attributes2)) @abc.abstractmethod def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs)
class Vni(ConfigurableBase): vni_id = managedattribute( name='vni_id', read_only=True, # read-only hash key doc='VNI ID (mandatory)') device = managedattribute(name='device', read_only=True, gettype=managedattribute.auto_unref) @property def testbed(self): return self.device.testbed nve = managedattribute(name='nve', default=None, gettype=managedattribute.auto_unref) @nve.deleter def nve(self): old_nve = self.nve del self._nve # may raise AttributeError if old_nve is not None: if self in old_nve.vnis: old_nve.remove_vni(self) @nve.setter def nve(self, nve): if nve is not None and not isinstance(nve, NveInterface): raise ValueError(nve) old_nve = self.nve if old_nve is not None: if self in old_nve.vnis: old_nve.remove_vni(self) self._nve = None if nve is not None: if nve.vnis_map.get(self.vni_id, None) is not self: assert nve.device is self.device nve.add_vni(self) self._nve = weakref.ref(nve) host_reachability_protocol = managedattribute( name='host_reachability_protocol', default=None, type=(None, managedattribute.test_istype(str))) load_balance = managedattribute(name='load_balance', default=None, type=(None, managedattribute.test_istype(str))) mcast_group = managedattribute(name='mcast_group', default=None, type=(None, managedattribute.test_istype(str))) vrf = managedattribute(name='vrf', default=None, type=(None, managedattribute.test_isinstance(Vrf))) def __init__(self, vni_id, device=None, nve=None, *args, **kwargs): if not device: if not nve: raise TypeError('provide either device or nve arguments') device = nve.device self._vni_id = int(vni_id) self._device = weakref.ref(device) super().__init__(*args, nve=nve, **kwargs) def _on_added_from_nve_interface(self, nve): self.nve = nve def _on_removed_from_nve_interface(self, nve): self.nve = None def __eq__(self, other): if not isinstance(other, Vni): return NotImplemented # return (self.device, self.vni_id) == (other.device, other.vni_id) return (self.vni_id, self.device) == (other.vni_id, other.device) def __lt__(self, other): if not isinstance(other, Vni): return NotImplemented return (self.device, self.vni_id) < (other.device, other.vni_id) def __hash__(self): return hash(self.vni_id)
class Interface(BaseInterface): ipv4addr = managedattribute( name='ipv4addr', finit=typedset(managedattribute.test_isinstance(IPv4Addr)).copy, type=typedset(managedattribute.test_isinstance(IPv4Addr))._from_iterable, doc='A `set` of IPv4Addr associated objects') def add_ipv4addr(self, ipv4addr=None, ipv4=None, prefix_length=None): if not ipv4addr and not (ipv4 and prefix_length): raise KeyError('At least ipv4addr or <ipv4(str), prefix_length(str)> is defined') if ipv4addr: self.ipv4addr.add(ipv4addr) else: ipv4_obj = IPv4Addr(self.device) ipv4_obj.ipv4 = ipv4 ipv4_obj.prefix_length = prefix_length self.ipv4addr.add(ipv4_obj) def remove_ipv4addr(self, ipv4addr): ipv4addr._device = None try: self.ipv4addr.remove(ipv4addr) except: pass ipv6addr = managedattribute( name='ipv6addr', finit=typedset(managedattribute.test_isinstance(IPv6Addr)).copy, type=typedset(managedattribute.test_isinstance(IPv6Addr))._from_iterable, doc='A `set` of IPv6Addr associated objects') def add_ipv6addr(self, ipv6addr): self.ipv6addr.add(ipv6addr) def remove_ipv6addr(self, ipv6addr): ipv6addr._device = None try: self.ipv6addr.remove(ipv6addr) except: pass ipv4 = managedattribute( name='ipv4', default=None, type=(None, IPv4Interface)) ipv6 = managedattribute( name='ipv6', default=None, type=(None, IPv6Interface)) vrf = managedattribute( name='vrf', default=None, type=(None, managedattribute.test_isinstance(Vrf))) # enabled enabled = managedattribute( name='enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc='Enable the selected interfac') # link_up_down_trap_enable link_up_down_trap_enable = managedattribute( name='link_up_down_trap_enable', default=None, type=(None, managedattribute.test_istype(bool)), doc='Allow SNMP LINKUP and LINKDOWN traps') # link-status link_status = managedattribute( name='link_status', default=None, type=(None, managedattribute.test_istype(bool)), doc='UPDOWN and CHANGE messages') # encapsulation class Encapsulation(Enum): dot1q = 'dot1q' isl = 'isl' priority_tagged = 'priority-tagged' encapsulation = managedattribute( name='encapsulation', default=None, type=(None, Encapsulation), doc='Set encapsulation type for an interface') # first_dot1q first_dot1q = managedattribute( name='first_dot1q', default=None, type=(None, managedattribute.test_istype(str)), doc='IEEE 802.1Q VLAN ID') # sedond_dot1q sedond_dot1q = managedattribute( name='second_dot1q', default=None, type=(None, managedattribute.test_istype(str)), doc='Second (inner) VLAN IDs') # native_vlan_dot1q native_vlan_dot1q = managedattribute( name='native_vlan_dot1q', default=None, type=(None, managedattribute.test_istype(bool)), doc='Make this as native vlan') # dhcp dhcp = managedattribute( name='dhcp', default=None, type=(None, managedattribute.test_istype(bool)), doc='IP Address negotiated via DHCP') # dhcp_client_id dhcp_client_id = managedattribute( name='dhcp_client_id', default=None, type=(None, managedattribute.test_istype(str)), doc='Specify client-id to use') # dhcp_hostname dhcp_hostname = managedattribute( name='dhcp_hostname', default=None, type=(None, managedattribute.test_istype(str)), doc='Specify value for hostname option') # unnumbered_intf_ref unnumbered_intf_ref = managedattribute( name='unnumbered_intf_ref', default=None, type=(None, managedattribute.test_istype(str)), doc='Enable IP processing without an explicit address') # ipv6_unnumbered_intf_ref ipv6_unnumbered_intf_ref = managedattribute( name='ipv6_unnumbered_intf_ref', default=None, type=(None, managedattribute.test_istype(str)), doc='Preferred interface for source address selection') # ipv6_enabled ipv6_enabled = managedattribute( name='ipv6_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc='Enable IPv6 on interface') # ipv6_autoconf ipv6_autoconf = managedattribute( name='ipv6_autoconf', default=None, type=(None, managedattribute.test_istype(bool)), doc='Obtain address using autoconfiguration') # ipv6_autoconf_default ipv6_autoconf_default = managedattribute( name='ipv6_autoconf_default', default=None, type=(None, managedattribute.test_istype(bool)), doc='Insert default route') # medium medium = managedattribute( name='medium', default=None, type=(None, Medium), doc='Configure Interface medium mode') # delay delay = managedattribute( name='delay', default=None, type=(None, managedattribute.test_istype(int)), doc='Specify interface throughput delay') # load_interval load_interval = managedattribute( name='load_interval', default=None, type=(None, managedattribute.test_istype(int)), doc='Specify interval for load calculation for an interface') # load_interval_counter load_interval_counter = managedattribute( name='load_interval_counter', default=None, type=(None, managedattribute.test_istype(int)), doc='Specify counter for the load interval') # flowcontrol_receive flowcontrol_receive = managedattribute( name='flowcontrol_receive', default=None, type=(None, managedattribute.test_istype(str)), doc='Receive pause frames') # flowcontrol_send flowcontrol_send = managedattribute( name='flowcontrol_send', default=None, type=(None, managedattribute.test_istype(str)), doc='Send pause frames') # bandwidth bandwidth = managedattribute( name='bandwidth', default=None, type=(None, managedattribute.test_istype(int)), doc='Set bandwidth informational parameter') # cdp cdp = managedattribute( name='cdp', default=False, type=(None, managedattribute.test_istype(bool)), doc='Configure CDP interface parameters') # description description = managedattribute( name='description', default=None, type=(None, managedattribute.test_istype(str)), doc='Enter description') # mtu mtu = managedattribute( name='mtu', default=None, type=(None, managedattribute.test_istype(int)), doc='Configure mtu for the port') # shutdown shutdown = managedattribute( name='shutdown', default=None, type=(None, managedattribute.test_istype(bool)), doc='Enable/disable an interface') switchport_enable = managedattribute( name='switchport_enable', default=None, type=(None, managedattribute.test_istype(bool)), doc='Configure switchport') class SWITCHPORTMODE(Enum): access = 'access' dot1q_tunnel = 'dot1q-tunnel' fex_fabric = 'fex-fabric' private_vlan = 'private-vlan' trunk = 'trunk' switchport_mode = managedattribute( name='switchport_mode', default=None, type=(None, SWITCHPORTMODE), doc= 'Interface switchport mode') evpn_multisite_fabric_tracking = managedattribute( name='evpn_multisite_fabric_tracking', default=None, type=(None, managedattribute.test_istype(bool)), doc='Configure evpn multisites fabric links') evpn_multisite_dci_tracking = managedattribute( name='evpn_multisite_dci_tracking', default=None, type=(None, managedattribute.test_istype(bool)), doc='Configure evpn multisites dci links') fabric_forwarding_mode = managedattribute( name='fabric_forwarding_mode', default=None, type=(None, managedattribute.test_istype(str)), doc='Configure fabric forwarding mode') ip_forward = managedattribute( name='ip_forward', default=None, type=(None, managedattribute.test_istype(bool)), doc='Configure ip forward') @abc.abstractmethod def build_config(self, *args, **kwargs): '''Derived OS-specific classes must provide build_config and build_unconfig methods. Example: Scenario #1: OS-specific interface module with inline configuration support:: # <os>/interface.py class Interface(genie.libs.conf.interface.Interface): def build_config(self, ...): ... return configurations Scenario #2: OS-specific interface module with context-specific configuration modules:: # <os>/interface.py class Interface(genie.libs.conf.interface.Interface): @abstract.lookup('context') def build_config(self, ...): \'\'\'Context-specific interface module provides configuration support.\'\'\' raise NotImplementedError # <os>/<context>/interface.py class Interface(abstract.AbstractImplementationBase): def build_config(self, ...): ... return configurations ''' raise NotImplementedError @abc.abstractmethod def build_unconfig(self, *args, **kwargs): '''Derived OS-specific classes must provide build_config and build_unconfig methods. See build_config documentation. ''' @classmethod def _build_name_to_class_map(cls): cls._name_to_class_map = {} for subcls in cls.__subclasses__(): subcls._build_name_to_class_map() cls._name_to_class_map.update(subcls._name_to_class_map) for k in cls.__dict__.get('_interface_name_types', ()): cls._name_to_class_map[k] = cls def generate_sub_interface(self, range=None, **kwargs): name = SubInterface._generate_unused_sub_interface_name( parent_interface=self, range=range) return Interface(device=self.device, name=name, **kwargs) @classmethod def _get_os_specific_Interface_class(cls, os): assert type(os) is str if False: # XXXJST TODO The abstract module needs to be enhanced. # Use it's API to perform a fast(cached) os-specific only lookup # without instantiating a Lookup instance everytime and be able to # work on classes / class methods. from genie.abstract import Lookup lib = Lookup(os) osInterface = lib.conf.interface.Interface if osInterface is Interface: raise ImportError( 'No Interface class found specific to OS {os!r}' \ .format(os=os)) else: mod = 'genie.libs.conf.interface.{os}'.\ format(os=os) OsInterfaceModule = importlib.import_module(mod) osInterface = OsInterfaceModule.Interface return osInterface def __new__(cls, *args, **kwargs): factory_cls = cls if factory_cls is Interface: # need to load the correct interface for the right os. if 'device' in kwargs: device = kwargs['device'] if not device.os and 'os' in kwargs['device'].__dict__: device.os = kwargs['device'].__dict__['os'] if device.os is None: raise AttributeError("Cannot convert interfaces for " "device {dev} as mandatory field " "'os' was not given in the " "yaml file".format(dev=device.name)) try: factory_cls = cls._get_os_specific_Interface_class(device.os) except (ImportError, AttributeError) as e: # it does not exist, then just use the default one, # but configuration is not possible pass elif not cls.device: raise TypeError('\'device\' argument missing') if factory_cls is not cls: self = factory_cls.__new__(factory_cls, *args, **kwargs) elif super().__new__ is object.__new__: self = super().__new__(factory_cls) else: self = super().__new__(factory_cls, *args, **kwargs) return self def __init__(self, *args, **kwargs): '''Base initialization for all Interface subclasses. This is not an abstract class since it may be used to instantiate generic interfaces for unsupported devices. All direct subclasses of Interface are abstract classes. ''' super().__init__(*args, **kwargs) if 'ipv4' not in kwargs: if self.ipv4: self.testbed.ipv4_cache.reserve(self.ipv4) if 'ipv6' not in kwargs: if self.ipv6: self.testbed.ipv6_cache.reserve(self.ipv6) parent_interface = managedattribute( name='parent_interface', read_only=True, doc='''The parent interface. Only meaningful for a few Interface subclasses.''') @parent_interface.defaulter def parent_interface(self): # If the 'parent' attribute is set in the pyATS YAML file, look it up parent_interface_name = getattr(self, 'parent', None) if parent_interface_name: return self.device.interfaces.get(parent_interface_name, None) return None parent_controller_type = managedattribute( name='parent_controller_type', default=None, read_only=True, doc='''The associated controller type. Only meaningful for a few Interface subclasses.''') @mixedmethod def parse_interface_name(inst, cls, *args, **kwargs): if inst: if args or kwargs: raise TypeError('Unexpected arguments: %r %r' % (args, kwargs)) return ParsedInterfaceName( name=inst.name, device=inst.device) else: return ParsedInterfaceName(*args, **kwargs) @property def interface_type(self): '''The type part of the interface name (str). Examples: GigabitEthernet0/0/0/0 -> 'GigabitEthernet' GigabitEthernet0/0/0/0.2 -> 'GigabitEthernet' Bundle-Ether1.2 -> 'Bundle-Ether' tunnel-te1 -> 'tunnel-te' GCC0 -> 'GCC0' ''' d_parsed = self.parse_interface_name() return d_parsed.type @property def interface_number(self): '''The number part of the interface name (int). Only valid for virtual interfaces constructed as "<type><number>" Examples: GigabitEthernet0/0/0/0 -> None GigabitEthernet0/0/0/0.2 -> None Bundle-Ether1.2 -> None tunnel-te1 -> 1 GCC0 -> None ''' d_parsed = self.parse_interface_name() if d_parsed.subintf: return None try: # Return only simple integers return int(d_parsed.number) except (TypeError, ValueError): # None or not a simple integer, it is a location return None @property def sub_interface_number(self): '''The sub-interface number part of the interface name (int). ''' d_parsed = self.parse_interface_name() if d_parsed.subintf_sep == '.': return int(d_parsed.subintf) return None @property def interface_location(self): '''The location part of the interface name (str). Examples: GigabitEthernet0/0/0/0 -> '0/0/0/0' GigabitEthernet0/0/0/0.2 -> '0/0/0/0' Bundle-Ether1.2 -> None tunnel-te1 -> None GCC0 -> None ''' # The Parent interface may know more about the location. parent_interface = self.parent_interface if parent_interface is not None: return parent_interface.interface_location d_parsed = self.parse_interface_name() try: # If it is a simple integer then it is not a location int(d_parsed.number) return None except (TypeError, ValueError): # None or not a simple integer, it is a location return d_parsed.number @mixedmethod def clean_interface_name(self, cls, interface_name=None): if interface_name is None: interface_name = self.name name_to_class_map = getattr(cls, '_name_to_class_map', {}) d_parsed = cls.parse_interface_name(interface_name) # check for exact match if d_parsed.type in name_to_class_map: return d_parsed.reconstruct() # Apply generic short->long mappings try: d_parsed.type = { 'g0': 'GCC0', 'g1': 'GCC1', 'dt': 'Odu-Group-Te', # what about Odu-Group-Mp? # Special case for at that matches both ATM and Auto-Template 'at': 'ATM', # Special case for gi that matches both GigabitEthernet and 'gi': 'GigabitEthernet', # Special case for TenGigECtrlr... both TeEC and EC forms seen on XR 'ec': 'TenGigECtrlr', 'teec': 'TenGigECtrlr', 'il': 'InterflexLeft', 'ir': 'InterflexRight', # TODO move to nxos # Special case for pw (NXOS pseudowire) that matches several 'pw': 'pseudowire', # Special case for se that matches both Serial and Service* # names 'se': 'Serial', 'sa': 'ServiceApp', 'si': 'ServiceInfra', # TODO #'tu' { # if { $name eq "Tu" } { # set name_lower "tunnel" # } else { # switch -exact -- $caas_os { # "IOS" - # "IOSXE" - # "NXOS" { # set name_lower "tunnel" # } # default { # set name_lower "tunnel-uti" # } # } # } #} # 'vl' { # # Special case for vl/Vl/VL that matches vlan on ACSW (but # # doesn't support short names), Vlan on IOS and VASILeft # # (hardcoded short name) # if { $name eq "VL" } { # set name_lower "vasileft" # } else { # set name_lower "vlan" # } # } 'vl': 'vlan', 'vr': 'VASIRight', # Special case for lo that matches both Loopback and # LongReachEthernet on Nexus (but doesn't support short names) 'lo': 'Loopback', }[d_parsed.type.lower()] except KeyError: for once in [1]: m = re.match(r'^o([01234](?:[EF][12]?)?)$', d_parsed.type, re.IGNORECASE) if m: d_parsed.type = 'OTU' + m.group(1).upper() break m = re.match(r'^d([01234](?:[EF][12]?)?)$', d_parsed.type, re.IGNORECASE) if m: d_parsed.type = 'ODU' + m.group(1).upper() break # There are still disambiguation issues for: # Port-channel # Service-Engine # ServiceApp # ServiceInfra # tunnel-ipsec # Virtual-Template # Virtual-TokenRing # MgmtIMA # MgmtMultilink # re-check for exact match if d_parsed.type in name_to_class_map: return d_parsed.reconstruct() matches = [] # check for different capitalization pat = d_parsed.type.lower() matches += [name for name in name_to_class_map if name.lower() == pat] if not matches: # check for start of name re_pat = r'^' + re.escape(d_parsed.type) + r'[^-]+$' matches += [name for name in name_to_class_map if re.match(re_pat, name, re.IGNORECASE)] # check for 2 letter abreviation of composite interface name if len(d_parsed.type) == 2: re_pat = r'^{}.*-{}.*$'.format(re.escape(d_parsed.type[0]), re.escape(d_parsed.type[1])) matches += [name for name in name_to_class_map if re.match(re_pat, name, re.IGNORECASE)] if len(matches) == 0: warnings.warn( 'Unknown interface type/name {!r}'.format( d_parsed.reconstruct()), UnknownInterfaceName) pass elif len(matches) == 1: d_parsed.type = matches[0] else: raise ValueError('Ambiguous interface type/name {!r} matches: {}'.format( d_parsed.reconstruct(), ', '.join(matches))) return d_parsed.reconstruct() @mixedmethod def short_interface_name(self, cls, interface_name=None): if interface_name is None: interface_name = self.name interface_name = (self or cls).clean_interface_name(interface_name) d_parsed = cls.parse_interface_name(interface_name) # When a dash is present, take the first letter of each word. # Otherwise, take the first 2 letters m = re.match('^([a-z])[a-z]*-([a-z])[a-z]*$', d_parsed.type, re.IGNORECASE) \ or re.match('^([a-z])([a-z])[a-z]*$', d_parsed.type, re.IGNORECASE) if m: d_parsed.type = m.group(1) + m.group(2) return d_parsed.reconstruct() return d_parsed.reconstruct() @property def sub_interfaces(self): return { interface for interface in self.device.interfaces if isinstance(interface, SubInterface) \ and interface.parent_interface is self}
class Dot1x(DeviceFeature): # Device Attributes enabled = managedattribute(name='enabled', default=None, type=(None, managedattribute.test_istype(bool))) system_auth_control = managedattribute( name='system_auth_control', default=None, type=(None, managedattribute.test_istype(bool))) supplicant_force_mcast = managedattribute( name='supplicant_force_mcast', default=None, type=(None, managedattribute.test_istype(bool))) # Credentials Attributes credential_profile = managedattribute( name='credential_profile', default=None, type=(None, managedattribute.test_istype(str))) credential_username = managedattribute( name='credential_username', default=None, type=(None, managedattribute.test_istype(str))) credential_pwd_type = managedattribute( name='credential_pwd_type', default=None, type=(None, managedattribute.test_in(['0', '7']))) credential_secret = managedattribute( name='credential_secret', default=None, type=(None, managedattribute.test_istype(str))) # Interfaces Attributes if_pae = managedattribute( name='if_pae', default=None, type=(None, managedattribute.test_in(['authenticator', 'supplicant', 'both']))) if_authen_eap_profile = managedattribute( name='if_authen_eap_profile', default=None, type=(None, managedattribute.test_istype(str))) if_supplicant_eap_profile = managedattribute( name='if_supplicant_eap_profile', default=None, type=(None, managedattribute.test_istype(str))) if_credentials = managedattribute(name='if_credentials', default=None, type=(None, managedattribute.test_istype(str))) if_closed = managedattribute(name='if_closed', default=None, type=(None, managedattribute.test_istype(bool))) if_port_control = managedattribute(name='if_port_control', default=None, type=(None, managedattribute.test_in([ 'auto', 'force-authorized', 'force-unauthorized' ]))) if_host_mode = managedattribute(name='if_host_mode', default=None, type=(None, managedattribute.test_in([ 'multi-auth', 'multi-domain', 'multi-host', 'single-host' ]))) class DeviceAttributes(DeviceSubAttributes): class InterfaceAttributes(InterfaceSubAttributes): def __init__(self, parent, key): self.interface_id = 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 CredentialsAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.credential_profile = key super().__init__(parent) credentials_attr = managedattribute(name='credentials_attr', read_only=True, doc=CredentialsAttributes.__doc__) @credentials_attr.initter def credentials_attr(self): return SubAttributesDict(self.CredentialsAttributes, parent=self) 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 DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): enabled_feature = managedattribute( name='enabled_feature', default=False, type=managedattribute.test_istype(bool), doc='''Argument to control 'mpls traffic-engineering' CLI''') @property def interfaces(self): device = self.device interfaces = set(self.parent.interfaces) #interfaces.update(*[link.interfaces for link in self.parent.links]) interfaces = {intf for intf in interfaces if intf.device is device} return frozenset(interfaces) @property def controllers(self): # TODO device = self.device controllers = set(self.parent.controllers) #controllers.update(*[link.interfaces for link in self.parent.links]) controllers = { intf for intf in controllers if intf.device is device } return frozenset(controllers) neighbors = managedattribute( name='neighbors', finit=typedset(IPv4NeighborSubAttributes).copy, type=typedset(IPv4NeighborSubAttributes)._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 InterfaceAttributes( genie.conf.base.attributes.InterfaceSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) 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(IPv4NeighborSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) 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 ControllerAttributes( genie.conf.base.attributes.InterfaceSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) controller_attr = managedattribute(name='controller_attr', read_only=True, doc=ControllerAttributes.__doc__) @controller_attr.initter def controller_attr(self): return SubAttributesDict(self.ControllerAttributes, parent=self) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs)
class StaticRouting(DeviceFeature, LinkFeature): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # ============================================= # Device attributes # ============================================= class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): # VrfAttributes class VrfAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.vrf = key super().__init__(parent=parent) # AddressFamilyAttribute class AddressFamilyAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.af = key super().__init__(parent) # RouteAttributes class RouteAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.route = key super().__init__(parent) # InterfaceAttributes class InterfaceAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.interface = key super().__init__(parent) 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) # NextHopAttributes class NextHopAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.nexthop = key super().__init__(parent) next_hop_attr = managedattribute( name='next_hop_attr', read_only=True, doc=NextHopAttributes.__doc__) @next_hop_attr.initter def next_hop_attr(self): return SubAttributesDict(self.NextHopAttributes, parent=self) route_attr = managedattribute(name='route_attr', read_only=True, doc=RouteAttributes.__doc__) @route_attr.initter def route_attr(self): return SubAttributesDict(self.RouteAttributes, parent=self) 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) vrf_attr = managedattribute(name='vrf_attr', read_only=True, doc=VrfAttributes.__doc__) @vrf_attr.initter def vrf_attr(self): return SubAttributesDict(self.VrfAttributes, parent=self) 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) # ============ managedattributes ============# vrf = managedattribute(name='vrf', default=None, type=managedattribute.test_istype(str), doc='Vrf Name') # address_family class ADDRESS_FAMILY(Enum): ipv4 = 'ipv4' ipv6 = 'ipv6' af = managedattribute(name='address_family', default='ipv4', type=(None, ADDRESS_FAMILY), doc='Configure static routing address family') route = managedattribute(name='route', default=None, type=(None, managedattribute.test_istype(str)), doc='route name') interface = managedattribute(name='interface', default=None, type=(None, managedattribute.test_istype(str)), doc='Interface name') if_nexthop = managedattribute(name='if_nexthop', default=None, type=(None, managedattribute.test_istype(str)), doc='Next hop') if_preference = managedattribute(name='if_preference', default=None, type=(None, managedattribute.test_istype(int)), doc='Preference') if_tag = managedattribute(name='if_tag', default=None, type=(None, managedattribute.test_istype(int)), doc='Tag') if_track = managedattribute(name='if_track', default=None, type=(None, managedattribute.test_istype(int)), doc='Track') if_nh_vrf = managedattribute(name='if_nh_vrf', default=None, type=(None, managedattribute.test_istype(str)), doc='vrf for next hop') nexthop = managedattribute(name='nexthop', default=None, type=(None, managedattribute.test_istype(str)), doc='Next hop') preference = managedattribute(name='preference', default=None, type=(None, managedattribute.test_istype(int)), doc='Preference') tag = managedattribute(name='tag', default=None, type=(None, managedattribute.test_istype(int)), doc='Tag') track = managedattribute(name='track', default=None, type=(None, managedattribute.test_istype(int)), doc='Track') nh_vrf = managedattribute(name='nh_vrf', default=None, type=(None, managedattribute.test_istype(str)), doc='vrf for next hop') # ========================================================= # build_config # ========================================================= def build_config(self, devices=None, interfaces=None, links=None, apply=True, attributes=None, **kwargs): attributes = AttributesHelper(self, attributes) cfgs = {} devices, interfaces, links = \ consolidate_feature_args(self, devices, interfaces, links) 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: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, interfaces=None, links=None, apply=True, attributes=None, **kwargs): attributes = AttributesHelper(self, attributes) cfgs = {} devices, interfaces, links = \ consolidate_feature_args(self, devices, interfaces, links) 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: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs
class RoutePolicyCondition(object): def op_contains(a, vb): try: vb = ip_address(vb) except ValueError: pass else: # b-ip in (a-ip|networks...) return any(vb in ip_network(va) for va in a) try: vb = ip_network(vb) except ValueError: pass else: # b-net in (a-ip|networks...) return any(vb == ip_network(va) for va in a) return vb in a def op_matches_any(a, vb): if isinstance(a, CommunitySet): a = a.communities sb = str(vb) return any( fnmatch.fnmatchcase(sb, a) if isinstance(a , str) else vb == a) op = managedattribute( name='op', type=managedattribute.test_in(( op_contains, op_matches_any, ))) operands = managedattribute( name='operands', type=managedattribute.test_tuple_of(_identity)) if_attr = managedattribute( name='if_attr', finit=RoutePolicyAttributes, type=managedattribute.test_istype(RoutePolicyAttributes)) else_attr = managedattribute( name='else_attr', finit=RoutePolicyAttributes, type=managedattribute.test_istype(RoutePolicyAttributes)) def __init__(self, op, *operands): self.op = op self.operands = operands super().__init__() def rpl_test_condition(self, obj, *, getattr=getattr): if self.op in ( RoutePolicyCondition.op_contains, RoutePolicyCondition.op_matches_any, ): a, b = self.operands return self.op(a, getattr(obj, b)) else: assert NotImplementedError(self.op)
class Vrf(DeviceFeature): vnis = managedattribute( name='vnis', #finit=typedset(managedattribute.test_isinstance(Evi)).copy, # circular dependency! #type=typedset(managedattribute.test_isinstance(Evi))._from_iterable) # circular dependency! doc='A `set` of Evi associated objects') @vnis.initter def vnis(self): from genie.libs.conf.evpn import Vni return typedset(managedattribute.test_isinstance(Vni)) @vnis.setter def vnis(self, value): from genie.libs.conf.evpn import Vni self._vnis = typedset(managedattribute.test_isinstance(Vni), value) @property def interfaces(self): return frozenset([ interface for interface in self.testbed.interfaces if interface.vrf is self ]) name = managedattribute(name='name', read_only=True) # read-only hash key description = managedattribute(name='description', default=None, type=(None, managedattribute.test_istype(str))) amt_flush_routes = managedattribute( name='amt_flush_routes', default=None, type=(None, managedattribute.test_istype(bool))) amt_pseudo_interface = managedattribute( name='amt_pseudo_interface', default=None, type=(None, managedattribute.test_isinstance(Interface))) fallback_vrf = managedattribute( name='fallback_vrf', default=None, # Self-reference; Done after: type=(None, managedattribute.test_isinstance(Vrf)) ) mhost_ipv4_default_interface = managedattribute( name='mhost_ipv4_default_interface', default=None, type=(None, managedattribute.test_isinstance(Interface))) mhost_ipv6_default_interface = managedattribute( name='mhost_ipv6_default_interface', default=None, type=(None, managedattribute.test_isinstance(Interface))) scale_mode = managedattribute(name='scale_mode', default=None, type=(None, managedattribute.test_in(('big', )))) remote_route_filtering = managedattribute( name='remote_route_filtering', default=None, type=(None, managedattribute.test_istype(bool))) vpn_id = managedattribute(name='vpn_id', default=None, type=(None, managedattribute.test_isinstance(VpnId))) rd = managedattribute(name='rd', default=None, type=(None, RouteDistinguisher, managedattribute.test_in(('auto', )))) address_families = managedattribute( name='address_families', finit=typedset(AddressFamily, {AddressFamily.ipv4_unicast}).copy, type=typedset(AddressFamily)._from_iterable) export_route_policy = managedattribute( name='export_route_policy', default=None, type=(None, managedattribute.test_istype(RoutePolicy))) export_route_targets = managedattribute( name='export_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) export_to_default_vrf_route_policy = managedattribute( name='export_to_default_vrf_route_policy', default=None, type=(None, managedattribute.test_istype(RoutePolicy))) export_to_vrf_allow_imported_vpn = managedattribute( name='export_to_vrf_allow_imported_vpn', default=None, type=(None, managedattribute.test_istype(bool))) export_to_vrf_import_stitching_rt = managedattribute( name='export_to_vrf_import_stitching_rt', default=None, type=(None, managedattribute.test_istype(bool))) import_from_default_vrf_route_policy = managedattribute( name='import_from_default_vrf_route_policy', default=None, type=(None, managedattribute.test_istype(RoutePolicy))) import_from_default_vrf_route_policy_maximum_prefixes = managedattribute( name='import_from_default_vrf_route_policy_maximum_prefixes', default=None, type=(None, managedattribute.test_istype(int))) import_from_default_vrf_advertise_as_vpn = managedattribute( name='import_from_default_vrf_advertise_as_vpn', default=None, type=(None, managedattribute.test_istype(bool))) import_route_policy = managedattribute( name='import_route_policy', default=None, type=(None, managedattribute.test_istype(RoutePolicy))) import_route_targets = managedattribute( name='import_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) maximum_prefix = managedattribute(name='maximum_prefix', default=None, type=(None, managedattribute.test_istype(int))) maximum_prefix_threshold = managedattribute( name='maximum_prefix_threshold', default=None, type=(None, managedattribute.test_istype(int))) maximum_prefix_reinstall_threshold = managedattribute( name='maximum_prefix_reinstall_threshold', default=None, type=(None, managedattribute.test_istype(int))) maximum_prefix_warning_only = managedattribute( name='maximum_prefix_warning_only', default=None, type=(None, managedattribute.test_istype(bool))) shutdown = managedattribute(name='shutdown', default=None, type=(None, managedattribute.test_istype(bool))) import_from_global_map = managedattribute( name='import_from_global_map', default=None, type=(None, managedattribute.test_istype(str))) export_to_global_map = managedattribute( name='export_to_global_map', default=None, type=(None, managedattribute.test_istype(str))) routing_table_limit_number = managedattribute( name='routing_table_limit_number', default=None, type=(None, managedattribute.test_istype(int))) alert_percent_value = managedattribute( name='alert_percent_value', default=None, type=(None, managedattribute.test_istype(int))) simple_alert = managedattribute(name='simple_alert', default=None, type=(None, managedattribute.test_istype(bool))) class RTTYPE(Enum): type1 = 'import' type2 = 'export' type3 = 'both' rt_type = managedattribute(name='rt_type', default=None, type=(None, RTTYPE), doc='import export or both') rt_mvpn = managedattribute(name='rt_mvpn', default=None, type=(None, managedattribute.test_istype(bool))) rt_evpn = managedattribute(name='rt_evpn', default=None, type=(None, managedattribute.test_istype(bool))) class PROTOCOL(Enum): type1 = 'mvpn' type2 = 'evpn' protocol = managedattribute(name='protocol', default=None, type=(None, PROTOCOL), doc='set mvpn or evpn ') vni = managedattribute(name='vni', default=None, type=(None, managedattribute.test_istype(int))) class DeviceAttributes(DeviceSubAttributes): @property def vnis(self): device = self.device return frozenset( [vni for vni in self.parent.vnis if vni.device is device]) @property def interfaces(self): device = self.device return frozenset([ interface for interface in self.parent.interfaces if interface.device is device ]) 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) 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): class RouteTargetAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.rt = key super().__init__(parent) # ProtocolAttribute class ProtocolAttributes(KeyedSubAttributes): def __init__(self, key, *args, **kwargs): self.protocol = key super().__init__(*args, **kwargs) protocol_attr = managedattribute( name='protocol_attr', read_only=True, doc=ProtocolAttributes.__doc__) @protocol_attr.initter def protocol_attr(self): return SubAttributesDict(self.ProtocolAttributes, parent=self) route_target_attr = managedattribute( name='route_target_attr', read_only=True, doc=RouteTargetAttributes.__doc__) @route_target_attr.initter def route_target_attr(self): return SubAttributesDict(self.RouteTargetAttributes, parent=self) def __init__(self, *args, **kwargs): self.address_family_attr = SubAttributesDict( self.AddressFamilyAttributes, parent=self) super().__init__(*args, **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 __init__(self, name, *args, **kwargs): assert isinstance(name, str) self._name = name super().__init__(*args, **kwargs) def __eq__(self, other): if not isinstance(other, Vrf): return NotImplemented return (self.name, self.testbed) \ == (other.name, other.testbed) def __lt__(self, other): if not isinstance(other, Vrf): return NotImplemented return (self.name, self.testbed) \ < (other.name, other.testbed) def __hash__(self): return hash(self.name) 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) cfgs = {key: value for key, value in cfgs.items() if value} 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) cfgs = {key: value for key, value in cfgs.items() if value} if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs @classmethod def learn_config(self, device, **kwargs): ''' A method that learn the device configurational state and create a conf object with the same configuration. Args: self (`obj`): Conf object. device (`obj`): The device that will be used to parse the command. ''' # Abstracting the show running vrf as per device os ret = Lookup.from_device(device) cmd = ret.parser.show_vrf.ShowRunningConfigVrf maker = ops_Base(device=device) maker.add_leaf(cmd=cmd, src='[vrf][(?P<vrf>.*)][rd]', dest='vrf[vrf][(?P<vrf>.*)][rd]') maker.add_leaf(cmd=cmd, src='[vrf][(?P<vrf>.*)]' '[vni]', dest='vrf[vrf][(?P<vrf>.*)]' '[vni]') maker.add_leaf(cmd=cmd, src='[vrf][(?P<vrf>.*)]' '[vrf_name]', dest='vrf[vrf][(?P<vrf>.*)]' '[vrf_name]') maker.add_leaf(cmd=cmd, src='[vrf][(?P<vrf>.*)][address_family]' '[(?P<af_name>.*)]', dest='vrf[vrf][(?P<vrf>.*)][address_family_attr]' '[(?P<af_name>.*)]') maker.add_leaf(cmd=cmd, src='[vrf][(?P<vrf>.*)][address_family]' '[(?P<af_name>.*)][route_target][(?P<rt>.*)][rt_type]', dest='vrf[vrf][(?P<vrf>.*)][address_family_attr]' '[(?P<af_name>.*)][route_target_attr][(?P<rt>.*)]' '[rt_type]') maker.add_leaf(cmd=cmd, src='[vrf][(?P<vrf>.*)][address_family]' '[(?P<af_name>.*)][route_target][(?P<rt>.*)]' '[protocol][(?P<protocol>.*)]', dest='vrf[vrf][(?P<vrf>.*)][address_family_attr]' '[(?P<af_name>.*)][route_target_attr][(?P<rt>.*)]' '[protocol_attr][(?P<protocol>.*)]') # A workaround to pass the context as in maker it expects Context.cli # not just a string 'cli. maker.context_manager[cmd] = Context.cli maker.make() # Take a copy of the object dictionary if not hasattr(maker, 'vrf'): maker.vrf = {} new_vrf = maker.vrf # List of mapped conf objects conf_obj_list = [] # Main structure attributes in the conf object structure_keys = [ 'address_family_attr', 'route_target_attr', 'protocol_attr' ] if len(new_vrf): for vrf in new_vrf['vrf'].keys(): if 'address_family_attr' in new_vrf['vrf'][vrf]: for af_name in new_vrf['vrf'][vrf][ 'address_family_attr'].keys(): if 'route_target' in new_vrf['vrf'][vrf][ 'address_family_attr'][af_name]: del new_vrf['vrf'][vrf]['address_family_attr'][ af_name]['route_target'] for i in list(new_vrf['vrf']): if 'address_family_attr' not in new_vrf['vrf'][i]: new_vrf['vrf'].pop(i) for vrf in new_vrf['vrf'].keys(): conf_obj = self(name=vrf) # Pass the class method not the instnace. maker.dict_to_obj(conf=conf_obj, \ struct=structure_keys, \ struct_to_map=new_vrf['vrf'][vrf]) conf_obj_list.append(conf_obj) # List of mapped conf objects return conf_obj_list
class TunnelEncryption(DeviceFeature): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # ============ managedattributes ============# enabled = managedattribute(name='enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable tunnelencryption feature.") policy_name = managedattribute(name='policy_name', default=None, type=(None, managedattribute.test_istype(str)), doc='create tunnel policy') class BIT_ENC(Enum): gcm_128_cmac = 'gcm-aes-xpn-128' gcm_256_cmac = 'gcm-aes-xpn-256' cipher_suite = managedattribute(name='cipher_suite', default=None, type=(None, BIT_ENC), doc='Set bit encryption algorithm') sak_rekey_time = managedattribute(name='sak_rekey_time', default=None, type=(None, managedattribute.test_istype(int)), doc='Set rekey time') peer_ip = managedattribute(name='peer_ip', default=None, type=(None, managedattribute.test_istype(str)), doc="tunnel peer ip") keychain_name = managedattribute(name='keychain_name', default=None, type=(None, managedattribute.test_istype(str)), doc="set key chain name") tunnelpolicy_name = managedattribute( name='tunnelpolicy_name', default=None, type=(None, managedattribute.test_istype(str)), doc="tunnel policyname") tunnel_source_interface = managedattribute( name='tunnel_source_interface', default=None, type=(None, managedattribute.test_istype(str)), doc='tunnel source interface') enabled_must_secure_policy = managedattribute( name='enabled_must_secure_policy', default=None, type=(None, managedattribute.test_istype(bool)), doc='tunnel-encryption must-secure-policy') # ============================================= # Device attributes # ============================================= class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): # tunnel encryption policy attributes class TunnelPolicyAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.policy_name = key super().__init__(parent) tunnelpolicy_attr = managedattribute( name='tunnelpolicy_attr', read_only=True, doc=TunnelPolicyAttributes.__doc__) @tunnelpolicy_attr.initter def tunnelpolicy_attr(self): return SubAttributesDict(self.TunnelPolicyAttributes, parent=self) class TunnelPeerIpAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.peer_ip = key super().__init__(parent) tunnelpeerip_attr = managedattribute( name='tunnelpeerip_attr', read_only=True, doc=TunnelPeerIpAttributes.__doc__) @tunnelpeerip_attr.initter def tunnelpeerip_attr(self): return SubAttributesDict(self.TunnelPeerIpAttributes, parent=self) 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) # ========================================================= # build_config # ========================================================= def build_config(self, devices=None, interfaces=None, links=None, apply=True, attributes=None, **kwargs): attributes = AttributesHelper(self, attributes) cfgs = {} devices, interfaces, links = \ consolidate_feature_args(self, devices, interfaces, links) 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: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, interfaces=None, links=None, apply=True, attributes=None, **kwargs): attributes = AttributesHelper(self, attributes) cfgs = {} devices, interfaces, links = \ consolidate_feature_args(self, devices, interfaces, links) 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: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs
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 pyats.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 Evi(ConfigurableBase): evi_id = managedattribute(name='evi_id', read_only=True, doc='int: EVI ID (read-only hash key)') evi_mode = managedattribute(name='evi_mode', default='vlan-based', type=(None, str)) device = managedattribute(name='device', read_only=True, gettype=managedattribute.auto_unref) @property def testbed(self): return self.device.testbed @property def evpn(self): return self.device.evpn advertise_mac = managedattribute(name='advertise_mac', default=None, type=(None, managedattribute.test_istype(bool))) control_word_disable = managedattribute( name='control_word_disable', default=None, type=(None, managedattribute.test_istype(bool))) class BgpAttributes(SubAttributes): enabled = managedattribute(name='enabled', default=False, type=managedattribute.test_istype(bool)) rd = managedattribute(name='rd', default=None, type=(None, RouteDistinguisher)) export_route_targets = managedattribute( name='export_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) export_route_target_none = managedattribute( name='export_route_target_none', default=None, type=(None, managedattribute.test_istype(bool))) import_route_targets = managedattribute( name='import_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) import_route_target_none = managedattribute( name='import_route_target_none', default=None, type=(None, managedattribute.test_istype(bool))) bgp = managedattribute(name='bgp', read_only=True, doc=BgpAttributes.__doc__) @bgp.initter def bgp(self): return self.BgpAttributes(parent=self) class LoadBalancingAttributes(SubAttributes): def __init__(self, _evi): self._evi = _evi super().__init__( # Evpn.device_attr[].load_balancing parent=None) @property def parent(self): return self._evi.evpn.device_attr[self.device].load_balancing @property def testbed(self): return self._evi.testbed @property def device_name(self): return self._evi.device_name @property def device(self): return self._evi.device load_balancing = managedattribute(name='load_balancing', read_only=True, doc=LoadBalancingAttributes.__doc__) @load_balancing.initter def load_balancing(self): return self.LoadBalancingAttributes(_evi=self) def __eq__(self, other): if not isinstance(other, Evi): return NotImplemented # return (self.device, self.evi_id) == (other.device, other.evi_id) return (self.evi_id, self.device) == (other.evi_id, other.device) def __lt__(self, other): if not isinstance(other, Evi): return NotImplemented return (self.device, self.evi_id) < (other.device, other.evi_id) def __hash__(self): return hash(self.evi_id) def __init__(self, device, evi_id, *args, **kwargs): self._evi_id = evi_id assert getattr(device, 'evpn', None) self._device = weakref.ref(device) self.evpn.add_evi(self) super().__init__(*args, **kwargs) def remove(self): try: self.evpn.remove_evi(self) except: pass self._device = None def __repr__(self): return '<%s object %r on %r at 0x%x>' % ( self.__class__.__name__, self.evi_id, self.device.name, id(self))
class Device(genie.conf.base.device.Device): def __new__(cls, name, *args, **kwargs): kwargs['name'] = name factory_cls = cls if factory_cls is Device: # need to load the correct Device for the right os. device_os = kwargs.get('os', None) if device_os is None: device = kwargs.get('device', None) if device is not None: device_os = getattr(device, 'os', None) if device_os is None: warnings.warn( 'Device {dev} OS is unknown;' ' Extended Device functionality will not be available:' ' mandatory field \'os\' was not given in the yaml' ' file'.format( dev=name, os=device_os), UnsupportedDeviceOsWarning) else: # Get the location where it will be loaded to mod = 'genie.libs.conf.device.{os}'.\ format(os=device_os) try: # import it OsDeviceModule = importlib.import_module(mod) factory_cls = OsDeviceModule.Device except (ImportError, AttributeError) as e: # it does not exist, then just use the default one. # At this time, this is expected, so don't warn at all. pass if factory_cls is not cls: self = factory_cls.__new__(factory_cls, *args, **kwargs) elif super().__new__ is object.__new__: self = super().__new__(factory_cls) else: self = super().__new__(factory_cls, *args, **kwargs) return self custom_config_cli = managedattribute( name='custom_config_cli', finit=str, type=managedattribute.test_istype(str)) custom_unconfig_cli = managedattribute( name='custom_unconfig_cli', finit=str, type=managedattribute.test_istype(str)) # nodename nodename = managedattribute( name='nodename', default=None, type=(None, managedattribute.test_istype(str)), doc="Hostname of the device") def learn_interface_mac_addresses(self): return NotImplemented # Not an error; Just not supported. def build_config(self, apply=True, attributes=None): """method to build the configuration of the device Api to build the configuration of a device object. This configuration depends of the configurable attributes of this object. Args: apply (`bool`): Apply the configuration on the device, unless it is set to False, then return the configuration, without applying it. Return: None if it was applied on the device `str` if apply was set to False Examples: >>> from genie.base.device import Device Create a Device obj >>> device = Device(name='PE1') assign configurable attributes to device obj >>> device.username = '******' >>> device.password = '******' build configuration and apply it on the device >>> device.build_config() build configuration and only return it >>> configuration = device.build_config(apply=False) """ attributes = AttributesHelper(self, attributes) configurations = CliConfigBuilder() # check added features and add to configurations if self.features: for feature in self.features: # check if feature in attributes feature_name = feature.__class__.__name__.lower() if isinstance(attributes.attributes, dict): if feature_name in attributes.attributes: attr = AttributesHelper2(feature, attributes.attributes[feature_name]) for _, sub, attributes2 in attr.mapping_items( 'device_attr', keys=set([self]), sort=True): configurations.append_block(sub.build_config(apply=False, attributes=attributes2.attributes)) else: attr = AttributesHelper2(feature, attributes) for _, sub, attributes2 in attr.mapping_items( 'device_attr', keys=set([self]), sort=True): configurations.append_block(sub.build_config(apply=False, attributes=attributes2)) configurations.append_block( attributes.format('{custom_config_cli}')) if apply: if configurations: self.configure(str(configurations), fail_invalid=True) else: # Return configuration return str(configurations) def build_unconfig(self, apply=True, attributes=None, **kwargs): """method to build the unconfiguration of the device object Api to build the unconfiguration of a device object. This unconfiguration depends of the configurable attributes of this object. Args: apply (`bool`): Apply the configuration on the device, unless it is set to False, then return the configuration, without applying it. Return: None if it was applied on the device `str` if apply was set to False Examples: >>> from genie.base.device import Device Create a Device obj >>> device = Device(name='PE1') build configuration and apply it on the device >>> device.build_unconfig() build configuration and only return it >>> configuration = device.build_unconfig(apply=False) """ attributes = AttributesHelper(self, attributes) configurations = CliConfigBuilder(unconfig=True) # check added features and add to configurations if self.features: for feature in self.features: # check if feature in attributes feature_name = feature.__class__.__name__.lower() if isinstance(attributes.attributes, dict): if feature_name in attributes.attributes: attr = AttributesHelper2(feature, attributes.attributes[feature_name]) for _, sub, attributes2 in attr.mapping_items( 'device_attr', keys=set([self]), sort=True): configurations.append_block(sub.build_unconfig(apply=False, attributes=attributes2.attributes)) else: attr = AttributesHelper2(feature, attributes) for _, sub, attributes2 in attr.mapping_items( 'device_attr', keys=set([self]), sort=True): configurations.append_block(sub.build_unconfig(apply=False, attributes=attributes2)) configurations.append_block( attributes.format('{custom_unconfig_cli}')) if apply: if configurations: self.configure(str(configurations), fail_invalid=True) else: # Return configuration return str(configurations) #@abc.abstractmethod def __init__(self, *args, **kwargs): '''Base initialization for all Device subclasses. This is not an abstract class since it may be used to instantiate generic unsupported devices. ''' super().__init__(*args, **kwargs) def get_os_specific_Interface_class(self): from genie.libs.conf.interface import Interface as xbuInterface return xbuInterface._get_os_specific_Interface_class(self.os) def clean_interface_name(self, interface_name): osInterface = self.get_os_specific_Interface_class() return osInterface.clean_interface_name(interface_name) def short_interface_name(self, interface_name): osInterface = self.get_os_specific_Interface_class() return osInterface.short_interface_name(interface_name)
class EmulatedDevice(Device): tgen_interface = managedattribute( name='tgen_interface', type=managedattribute.test_auto_ref( managedattribute.test_isinstance(Interface)), gettype=managedattribute.auto_unref) @property def tgen_device(self): return self.tgen_interface.device tgen_handle = managedattribute( name='tgen_handle', default=None, type=(None, managedattribute.test_istype(str)), doc='''The emulated device handle, as understood by HLTAPI/low-level vendor APIs.''') emulated_loopback = managedattribute( name='emulated_loopback', default=None, #type=(None, managedattribute.test_isinstance(EmulatedLoopbackInterface)), ) emulated_interface = managedattribute( name='emulated_interface', default=None, #type=(None, managedattribute.test_isinstance(EmulatedInterface)), ) emulated_link = managedattribute( name='emulated_link', default=None, type=(None, managedattribute.test_isinstance(EmulatedLink)), ) @property def tgen_port_handle(self): return self.tgen_interface.tgen_port_handle @property def os(self): return self.tgen_device.os @property def context(self): return self.tgen_device.context @property def type(self): return self.tgen_device.type gateway_interface = managedattribute( name='gateway_interface', type=(None, managedattribute.test_isinstance(Interface))) @gateway_interface.defaulter def gateway_interface(self): return self.tgen_interface.gateway_interface @property def gateway_ipv4(self): gateway_interface = self.gateway_interface ipv4 = gateway_interface and gateway_interface.ipv4 return ipv4 and ipv4.ip @property def gateway_ipv6(self): gateway_interface = self.gateway_interface ipv6 = gateway_interface and gateway_interface.ipv6 return ipv6 and ipv6.ip def __new__(cls, name, *args, **kwargs): kwargs['name'] = name factory_cls = cls if factory_cls is EmulatedDevice: try: tgen_interface = kwargs['tgen_interface'] except KeyError: raise TypeError('Missing tgen_interface keyword argument') # need to load the correct Device for the right os. os = tgen_interface.device.os # Get the location where it will be loaded to mod = 'genie.libs.conf.device.{os}'.\ format(os=os) # import it OsDeviceModule = importlib.import_module(mod) factory_cls = OsDeviceModule.EmulatedDevice if factory_cls is not cls: self = factory_cls.__new__(factory_cls, *args, **kwargs) elif super().__new__ is object.__new__: self = super().__new__(factory_cls) else: self = super().__new__(factory_cls, *args, **kwargs) return self @abc.abstractmethod def __init__(self, name, *args, tgen_interface, create_loopback=True, create_interface=True, create_link=True, address_families={AddressFamily.ipv4}, lo_ipv4=None, lo_ipv6=None, ipv4=None, ipv6=None, mac_address=None, **kwargs): self.tgen_interface = tgen_interface # A lot may depend on this super().__init__(*args, name=name, **kwargs) tgen_device = self.tgen_device if create_loopback or create_interface: from genie.libs.conf.interface import EmulatedInterface from genie.libs.conf.interface import _get_descendent_subclass emul_os_interface_class = EmulatedInterface._get_os_specific_EmulatedInterface_class(self.os) if create_loopback: if self.os == 'pagent': # Pagent requires router IDs to have lower values than interfaces; # Promise an address in a class A network. # Always need IPv4 loopback if lo_ipv4 is None and AddressFamily.ipv4 in address_families: lo_ipv4 = self.testbed.ipv4_cache.reserve(type='A', prefixlen=32)[0] if lo_ipv6 is None and AddressFamily.ipv6 in address_families: pass # lo_ipv6 = self.testbed.ipv6_cache.reserve(TODO)[0] else: # Always need IPv4 loopback if lo_ipv4 is None and AddressFamily.ipv4 in address_families: lo_ipv4 = self.testbed.ipv4_cache.reserve(prefixlen=32)[0] if lo_ipv6 is None and AddressFamily.ipv6 in address_families: lo_ipv6 = self.testbed.ipv6_cache.reserve(prefixlen=128)[0] from genie.libs.conf.interface import LoopbackInterface emul_lo_interface_class = _get_descendent_subclass(emul_os_interface_class, LoopbackInterface) self.emulated_loopback = emul_lo_interface_class( device=self, name='Loopback0', ipv4=lo_ipv4, lo_ipv6=lo_ipv6, ) if create_interface: router_interface = self.gateway_interface from genie.libs.conf.interface import EthernetInterface emul_phy_interface_class = _get_descendent_subclass(emul_os_interface_class, EthernetInterface) # TODO support other interface base classes #### set vRtrIntf [lindex [enaTbGetInterfacePeer $vTgenIntf -linktype {iflink ifmesh}] 0] if self.os == 'pagent': # XXXJST TODO -- Pagent can use multiple emulations (OSPF) but they overwrite the main port's IP if ipv4 is None and AddressFamily.ipv4 in address_families: ipv4 = self.tgen_interface.ipv4 if ipv6 is None and AddressFamily.ipv6 in address_families: ipv6 = self.tgen_interface.ipv6 if mac_address is None: mac_address = self.tgen_interface.mac_address self.emulated_interface = emul_phy_interface_class( device=self, name=self.tgen_interface.name, mac_address=mac_address, ipv4=ipv4, ipv6=ipv6, ) else: if ipv4 is None and AddressFamily.ipv4 in address_families: base_ipv4 = self.tgen_interface.ipv4 assert base_ipv4 broadcast_address = base_ipv4.network.broadcast_address for n in itertools.count(1): ipv4_ip = base_ipv4.ip + n if ipv4_ip == broadcast_address: raise RuntimeError('No ipv4 addresses left in %r\'s network' % (base_ipv4,)) ipv4 = IPv4Interface((ipv4_ip, base_ipv4.network.prefixlen)) if not self.testbed.find_interfaces(ipv4=ipv4): break if ipv6 is None and AddressFamily.ipv6 in address_families: base_ipv6 = self.tgen_interface.ipv6 assert base_ipv6 broadcast_address = base_ipv6.network.broadcast_address for n in itertools.count(1): ipv6_ip = base_ipv6.ip + n if ipv6_ip == broadcast_address: raise RuntimeError('No ipv6 addresses left in %r\'s network' % (base_ipv6,)) ipv6 = IPv6Interface((ipv6_ip, base_ipv6.network.prefixlen)) if not self.testbed.find_interfaces(ipv6=ipv6): break if mac_address is None: mac_address = self.testbed.mac_cache.reserve(count=1)[0] self.emulated_interface = emul_phy_interface_class( device=self, name='Ethernet0', ipv4=ipv4, ipv6=ipv6, mac_address=mac_address, ) if create_link: self.emulated_link = EmulatedLink( name='{}-emulated_link'.format(name), interfaces=[self.emulated_interface, router_interface]) def __repr__(self): try: name = self.name tgen_interface = self.tgen_interface assert tgen_interface tgen_device = tgen_interface.device assert tgen_device except: return super().__repr__() else: return '<%s object %r on %s %s at 0x%x>' % ( self.__class__.__name__, name, tgen_device.name, tgen_interface.name, id(self)) @abc.abstractmethod def build_config(self, *args, **kwargs): return '' @abc.abstractmethod def build_unconfig(self, *args, **kwargs): return ''
class LagInterface(VirtualInterface): enabled_lacp = managedattribute( name='enabled_lacp', default=None, type=(None, managedattribute.test_istype(bool)), doc= 'enabled_lacp') lag_lacp_system_priority = managedattribute( name='lag_lacp_system_priority', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_lacp_system_priority') lag_lacp_max_bundle = managedattribute( name='lag_lacp_max_bundle', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_lacp_max_bundle') lag_lacp_min_bundle = managedattribute( name='lag_lacp_min_bundle', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_lacp_min_bundle') lag_bfd_v4_destination = managedattribute( name='lag_bfd_v4_destination', default=None, type=(None, managedattribute.test_istype(str)), doc= 'lag_bfd_v4_destination') lag_bfd_v4_fast_detect = managedattribute( name='lag_bfd_v4_fast_detect', default=None, type=(None, managedattribute.test_istype(bool)), doc= 'lag_bfd_v4_fast_detect') lag_bfd_v4_min_interval = managedattribute( name='lag_bfd_v4_min_interval', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_bfd_v4_min_interval') lag_bfd_v6_destination = managedattribute( name='lag_bfd_v6_destination', default=None, type=(None, managedattribute.test_istype(str)), doc= 'lag_bfd_v6_destination') lag_bfd_v6_fast_detect = managedattribute( name='lag_bfd_v6_fast_detect', default=None, type=(None, managedattribute.test_istype(bool)), doc= 'lag_bfd_v6_fast_detect') lag_bfd_v6_min_interval = managedattribute( name='lag_bfd_v6_min_interval', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_bfd_v6_min_interval')
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 Vpc(DeviceFeature): # enabled enabled = managedattribute( name='enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable Vpc feature.") # domain_id domain_id = managedattribute( name='domain_id', default=None, type=(None, managedattribute.test_istype(int)), doc="Vpc Domain id.") # auto_recovery_enabled auto_recovery_enabled = managedattribute( name='auto_recovery_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="VPC settings to enable auto recovery if peer is presumed non-operational.") # auto_recovery_intvl [60-3600] auto_recovery_interval = managedattribute( name='auto_recovery_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="Duration to wait before assuming peer dead and restoring vpcs.") # delay_restore_vpc [1-3600] delay_restore_vpc = managedattribute( name='delay_restore_vpc', default=None, type=(None, managedattribute.test_istype(int)), doc="Delay time in bringing up the vPC links.") # delay_restore_svi [1-3600] delay_restore_svi = managedattribute( name='delay_restore_svi', default=None, type=(None, managedattribute.test_istype(int)), doc="Delay time in bringing up interface-vlan.") # delay_restore_orphan [0-300] delay_restore_orphan = managedattribute( name='delay_restore_orphan', default=None, type=(None, managedattribute.test_istype(int)), doc="Delay time in bringing up orphan port.") # exclude_svi dual_active_exclude_svi = managedattribute( name='dual_active_exclude_svi', default=None, type=(None, managedattribute.test_istype(int)), doc="Svis to be exclude from suspension when dual-active.") # fast_convergence_enabled fast_convergence_enabled = managedattribute( name='fast_convergence_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable vPC fast-convergence.") # graceful_cc_enabled graceful_cc_enabled = managedattribute( name='graceful_cc_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable graceful type-1 consistency check.") # ip_arp_sync_enabled ip_arp_sync_enabled = managedattribute( name='ip_arp_sync_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable CFS ip arp synchronization.") # ipv6_nd_sync_enabled ipv6_nd_sync_enabled = managedattribute( name='ipv6_nd_sync_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable CFS ipv6 nd synchronization.") # l3_peer_router_enabled l3_peer_router_enabled = managedattribute( name='l3_peer_router_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Layer 3 peer router enabled.") # l3_peer_router_syslog_enabled l3_peer_router_syslog_enabled = managedattribute( name='l3_peer_router_syslog_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Layer 3 peer router syslog messages enabled.") # l3_peer_router_syslog_intvl [1-3600] l3_peer_router_syslog_intvl = managedattribute( name='l3_peer_router_syslog_intvl', default=None, type=(None, managedattribute.test_istype(int)), doc="Layer 3 peer router, How many seconds to print a syslog.") # mac_bpdu_src_ver mac_bpdu_src_ver = managedattribute( name='mac_bpdu_src_ver', default=None, type=(None, managedattribute.test_istype(int)), doc="Use version 2 bpdu source mac-address.") # peer_gw_exlude_enabled peer_gw_enabled = managedattribute( name='peer_gw_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable L3 forwarding for packets destined to peer's gateway mac-address.") # peer_gw_exlude_vlan peer_gw_exlude_vlan = managedattribute( name='peer_gw_exlude_vlan', default=None, type=(None, managedattribute.test_istype(int)), doc="VLANs to be excluded from peer-gateway functionality.") # peer_switch_enabled peer_switch_enabled = managedattribute( name='peer_switch_enabled', default=None, type=(None, managedattribute.test_istype(bool)), doc="Enable peer switch on vPC pair switches.") # role_priority [1-65535] role_priority = managedattribute( name='role_priority', default=None, type=(None, managedattribute.test_istype(int)), doc="Vpc role priority value.") # shutdown shutdown = managedattribute( name='shutdown', default=None, type=(None, managedattribute.test_istype(bool)), doc="Suspend vPC locally.") # system_mac system_mac = managedattribute( name='system_mac', default=None, type=(None, managedattribute.test_istype(str)), doc="System mac address.") # system_priority [1-65535] system_priority = managedattribute( name='system_priority', default=None, type=(None, managedattribute.test_istype(int)), doc="System priority value.") # track [1-65535] track = managedattribute( name='track', default=None, type=(None, managedattribute.test_istype(int)), doc="Tracked object value.") # virtual_peer_link_ip virtual_peer_link_ip = managedattribute( name='virtual_peer_link_ip', default=None, type=(None, managedattribute.test_istype(str)), doc="Virtual peer-link destination ip.") # keepalive_dst_ip keepalive_dst_ip = managedattribute( name='keepalive_dst_ip', default=None, type=(None, managedattribute.test_istype(str)), doc="Destination ip address of peer switch for keepalive messages.") # keepalive_src_ip keepalive_src_ip = managedattribute( name='keepalive_src_ip', default=None, type=(None, managedattribute.test_istype(str)), doc="Source ip address for keepalive messages.") # keepalive_vrf keepalive_vrf = managedattribute( name='keepalive_vrf', default=None, type=(None, managedattribute.test_istype(str)), doc="Vrf to be used for hello messages.") # keepalive_udp_port keepalive_udp_port = managedattribute( name='keepalive_udp_port', default=None, type=(None, managedattribute.test_istype(int)), doc="UDP port number used for hello.") # keepalive_interval keepalive_interval = managedattribute( name='keepalive_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="Hello time interval in milliseconds.") # keepalive_timeout keepalive_timeout = managedattribute( name='keepalive_timeout', default=None, type=(None, managedattribute.test_istype(int)), doc="Hold timeout to ignore stale peer alive messages.") # keepalive_tos keepalive_tos = managedattribute( name='keepalive_tos', default=None, type=(None, managedattribute.test_istype(str)), doc="Type of Service(IPV4)/Traffic Class(IPV6).") # keepalive_tos_byte keepalive_tos_byte = managedattribute( name='keepalive_tos_byte', default=None, type=(None, managedattribute.test_istype(int)), doc="Type of Service Byte (IPv4)/Traffic Class Octet(IPv6).") # keepalive_precedence keepalive_precedence = managedattribute( name='keepalive_precedence', default=None, type=(None, managedattribute.test_istype(str)), doc="Precedence Value.") class DeviceAttributes(DeviceSubAttributes): class DomainAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.domain_id = key super().__init__(parent=parent) domain_attr = managedattribute( name='domain_attr', read_only=True, doc=DomainAttributes.__doc__) @domain_attr.initter def domain_attr(self): return SubAttributesDict( self.DomainAttributes, parent=self) 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 build_config(self, devices=None, apply=True, attributes=None): 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', sort=True): cfgs[key] = sub.build_config(apply=False, attributes=attributes2) if apply: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, apply=True, attributes=None): 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', sort=True): cfgs[key] = sub.build_unconfig(apply=False, attributes=attributes2) if apply: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs
class Pim(Routing, DeviceFeature, InterfaceFeature): address_families = managedattribute( name='address_families', finit=typedset(AddressFamily, {AddressFamily.ipv4}).copy, type=typedset(AddressFamily)._from_iterable) sparse = managedattribute(name='sparse', default=None, type=(None, managedattribute.test_istype(bool))) rp_address = managedattribute(name='rp_address', default=None, type=(None, IPv4Address, IPv6Address)) # ==================== NXOS specific ==================== # feature pim # feature pim6 enabled = managedattribute( name='enabled', default=False, type=(None, managedattribute.test_istype(bool)), doc='Enable or disable both feature pim and feature pim6') # feature pim enabled_pim = managedattribute(name='enabled_pim', default=False, type=(None, managedattribute.test_istype(bool)), doc='Enable or disable feature pim') # feature_pim6 enabled_pim6 = managedattribute(name='enabled_pim6', default=False, type=(None, managedattribute.test_istype(bool)), doc='Enable or disable feature pim6') # =========================================================== # enable_bidir enabled_bidir = managedattribute( name='enabled_bidir', default=False, type=(None, managedattribute.test_istype(bool)), doc='Enable or disable feature bidir only for iosxe') # ==== PIM Auto-RP ======= auto_rp = managedattribute( name='auto_rp', default=False, type=(None, managedattribute.test_istype(bool)), doc="Auto-RP protocol RP-distribution configuration") send_rp = managedattribute( name='send_rp', default=False, type=(None, managedattribute.test_istype(bool)), doc="Configures router to send Auto-RP Announce messages") send_rp_announce_rp_group = managedattribute( name='send_rp_announce_rp_group', default=None, type=(None, managedattribute.test_istype(str)), doc="IP address of RP for group") send_rp_announce_intf = managedattribute( name='send_rp_announce_intf', default=None, type=(None, managedattribute.test_istype(str)), doc="auto-rp interface") send_rp_announce_group_list = managedattribute( name='send_rp_announce_group_list', default=None, type=(None, managedattribute.test_istype(str)), doc="Group range list") send_rp_announce_route_map = managedattribute( name='send_rp_announce_route_map', default=None, type=(None, managedattribute.test_istype(str)), doc=" Group range policy for Auto-RP Candidate RP") send_rp_announce_prefix_list = managedattribute( name='send_rp_announce_prefix_list', default=None, type=(None, managedattribute.test_istype(str)), doc="Prefix List policy for Auto-RP Candidate RP") send_rp_announce_interval = managedattribute( name='send_rp_announce_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="Auto-RP Announce message transmission interval") send_rp_announce_scope = managedattribute( name='send_rp_announce_scope', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure the scope of Auto-RP Announce messages") send_rp_announce_bidir = managedattribute( name='send_rp_announce_bidir', default=False, type=(None, managedattribute.test_istype(bool)), doc="Group range advertised in PIM bidirectional mode") auto_rp_discovery = managedattribute( name='auto_rp_discovery', default=False, type=(None, managedattribute.test_istype(bool)), doc="Configures router as an Auto-RP RP-mapping agent") send_rp_discovery = managedattribute( name='send_rp_discovery', default=False, type=(None, managedattribute.test_istype(bool)), doc="Configures router to send Auto-RP Discovery messages") send_rp_discovery_intf = managedattribute( name='send_rp_discovery_intf', default=None, type=(None, managedattribute.test_istype(str)), doc="Auto-RP Discovery messages interface") send_rp_discovery_scope = managedattribute( name='send_rp_discovery_scope', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure the scope of Auto-RP Discovery messages") send_rp_discovery_interval = managedattribute( name='send_rp_discovery_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="Auto-RP Discovery message transmission interval") autorp_listener = managedattribute( name='autorp_listener', default=False, type=(None, managedattribute.test_istype(bool)), doc="Listen to Auto-RP messages") # ==== PIM BSR ======= # === bsr-candidate === bsr_candidate_interface = managedattribute( name='bsr_candidate_interface', default=None, type=(None, managedattribute.test_istype(str)), doc="Configure router as a Bootstrap Router candidate interface") bsr_candidate_hash_mask_length = managedattribute( name='bsr_candidate_hash_mask_length', default=None, type=(None, managedattribute.test_istype(int)), doc="Hash mask length used in Bootstrap messages") bsr_candidate_priority = managedattribute( name='bsr_candidate_priority', default=None, type=(None, managedattribute.test_istype(int)), doc="BSR priority used in Bootstrap messages") bsr_candidate_interval = managedattribute( name='bsr_candidate_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="Bootstrap message transmission interval") bsr_candidate_accept_rp_acl = managedattribute( name='bsr_candidate_accept_rp_acl', default=None, type=(None, managedattribute.test_istype(str), managedattribute.test_istype(int)), doc="bsr_candidate_accept_rp_acl") bsr_candidate_address = managedattribute( name='bsr_candidate_address', default=None, type=(None, managedattribute.test_istype(str)), doc="bsr_candidate_address") # === bsr rp-candidate ==== bsr_rp_candidate_interface = managedattribute( name='bsr_rp_candidate_interface', default=None, type=(None, managedattribute.test_istype(str)), doc="Configure router as a Rendezvous Point (RP) candidate interface") bsr_rp_candidate_group_list = managedattribute( name='bsr_rp_candidate_group_list', default=None, type=(None, managedattribute.test_istype(str)), doc="Group range list") bsr_rp_candidate_route_map = managedattribute( name='bsr_rp_candidate_route_map', default=None, type=(None, managedattribute.test_istype(str)), doc="Group range policy for Candidate RP") bsr_rp_candidate_prefix_list = managedattribute( name='bsr_rp_candidate_prefix_list', default=None, type=(None, managedattribute.test_istype(str)), doc="Prefix List policy for Candidate RP") bsr_rp_candidate_priority = managedattribute( name='bsr_rp_candidate_priority', default=None, type=(None, managedattribute.test_istype(int)), doc="Group range policy for Candidate RP") bsr_rp_candidate_interval = managedattribute( name='bsr_rp_candidate_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="Bootstrap message transmission interval") bsr_rp_candidate_bidir = managedattribute( name='bsr_rp_candidate_bidir', default=False, type=(None, managedattribute.test_istype(bool)), doc="Group range advertised in PIM bidirectional mode") bsr_rp_candidate_address = managedattribute( name='bsr_rp_candidate_address', default=None, type=(None, managedattribute.test_istype(str)), doc="bsr_rp_candidate_address") # # ==== PIM Other ======= accept_register = managedattribute( name='accept_register', default=None, type=(None, managedattribute.test_istype(str)), doc="A route-map name") # only used for nxos ipv4 accept_register_prefix_list = managedattribute( name='accept_register_prefix_list', default=None, type=(None, managedattribute.test_istype(str)), doc="Prefix List policy for Registers") log_neighbor_changes = managedattribute( name='log_neighbor_changes', default=False, type=(None, managedattribute.test_istype(bool)), doc="Log up/down PIM neighbor transitions") register_source = managedattribute( name='accept_register_route_map', default=None, type=(None, managedattribute.test_istype(str)), doc="Configure source address for Register messages") sg_expiry_timer = managedattribute( name='sg_expiry_timer', default=None, type=(None, managedattribute.test_istype(int)), doc="Adjust expiry time for PIM ASM (S,G) routes") # NXOS only sg_expiry_timer_infinity = managedattribute( name='sg_expiry_timer_infinity', default=False, type=(None, managedattribute.test_istype(bool)), doc="Never expire (S,G) route due to data inactivity") sg_expiry_timer_sg_list = managedattribute( name='sg_expiry_timer_sg_list', default=None, type=(None, managedattribute.test_istype(str)), doc="Specifies route-map for (S,G)s to apply the expiry timer") sg_expiry_timer_prefix_list = managedattribute( name='sg_expiry_timer_prefix_list', default=None, type=(None, managedattribute.test_istype(str)), doc="Specifies prefix-list for (S,G)s to apply the expiry timer") class SPT_SWITCH_INFINITY(Enum): active = 0 passive = 'infinity' spt_switch_infinity = managedattribute( name='spt_switch_infinity', default=False, type=(None, SPT_SWITCH_INFINITY), doc="Source-tree switching threshold") spt_switch_policy = managedattribute( name='spt_switch_policy', default=None, type=(None, managedattribute.test_istype(str), managedattribute.test_istype(int)), doc="Specify group ranges through policy") # ==== PIM AddressFamily Interface ======= class MODE(Enum): mode1 = 'dense-mode' mode2 = 'sparse-mode' mode3 = 'sparse-dense-mode' mode = managedattribute(name='mode', default=None, type=(None, MODE), doc="pim mode - only 'sparse-mode' valid for NXOS") boundary = managedattribute(name='boundary', default=None, type=(None, managedattribute.test_istype(str), managedattribute.test_istype(int)), doc="ip multicast boundary/jp_policy") boundary_filter_autorp = managedattribute( name='boundary_filter_autorp', default=None, type=(None, managedattribute.test_istype(bool)), doc="boundary group") boundary_in = managedattribute(name='boundary_in', default=False, type=(None, managedattribute.test_istype(bool)), doc="boundary direction in/jp_policy_in") boundary_out = managedattribute(name='boundary_out', default=False, type=(None, managedattribute.test_istype(bool)), doc="boundary direction out/jp_policy_out") bsr_border = managedattribute( name='bsr_border', default=False, type=(None, managedattribute.test_istype(bool)), doc="bsr border - prevents both BSR and Auto-RP") hello_interval = managedattribute(name='hello_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="hello interval") hello_interval_msec = managedattribute( name='hello_interval_msec', default=None, type=(None, managedattribute.test_istype(int)), doc="hello interval msec") dr_priority = managedattribute(name='dr_priority', default=None, type=(None, managedattribute.test_istype(int)), doc="pim dr-priority") neighbor_filter = managedattribute( name='neighbor_filter', default=None, type=(None, managedattribute.test_istype(str), managedattribute.test_istype(int)), doc="pim neighbor filter") # NXOS only neighbor_filter_prefix_list = managedattribute( name='neighbor_filter_prefix_list', default=None, type=(None, managedattribute.test_istype(str)), doc="pim neighbor filter prefix list") @property def vrfs(self): return \ self.force_vrfs | \ {intf.vrf for intf in self.interfaces} force_vrfs = managedattribute(name='force_vrfs', read_only=True, finit=set, gettype=frozenset) # XXXJST TODO force_vrfs needs to also be accessible per-device. Being read_only, that can't happen def add_force_vrf(self, vrf): assert vrf is None or isinstance(vrf, Vrf) self.force_vrfs # init! self._force_vrfs.add(vrf) def remove_force_vrf(self, vrf): assert vrf is None or isinstance(vrf, Vrf) self.force_vrfs # init! self._force_vrfs.remove(vrf) class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): address_families = managedattribute( name='address_families', type=typedset(AddressFamily)._from_iterable) @property def vrfs(self): return \ self.force_vrfs | \ {intf.vrf for intf in self.interfaces} @address_families.defaulter def address_families(self): return frozenset(self.parent.address_families) class VrfAttributes(VrfSubAttributes): 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): rp_addresses = managedattribute( name='rp_addresses', finit=typedset( managedattribute.test_isinstance(RPAddressGroup)).copy, type=typedset( managedattribute.test_isinstance( RPAddressGroup))._from_iterable, doc='A `set` of RPAddressGroup associated objects') def add_static_rp(self, rp_addresses): self.rp_addresses.add(rp_addresses) def remove_static_rp(self, rp_addresses): rp_addresses._device = None try: self.rp_addresses.remove(rp_addresses) except: pass class InterfaceAttributes(InterfaceSubAttributes): pass 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) 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) vrf_attr = managedattribute(name='vrf_attr', read_only=True, doc=VrfAttributes.__doc__) @vrf_attr.initter def vrf_attr(self): return SubAttributesDict(self.VrfAttributes, 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 @classmethod def learn_config(self, device, **kwargs): ''' A method that learn the device configurational state and create a conf object with the same configuration. Args: self (`obj`): Conf object. device (`obj`): The device that will be used to parse the command. ''' if kwargs.get('attributes', None): kwargs['attributes'].extend(['v4_vrfs_list', 'v6_vrfs_list']) # Abstracting the show running bgp as per device os ret = Lookup.from_device(device) cmd = ret.parser.show_pim.ShowRunningConfigPim maker = ops_Base(device=device, **kwargs) maker.add_leaf(cmd=cmd, src='[feature_pim]', dest='pim[enabled_pim]', address_family='ipv4', pip_str='feature') maker.add_leaf(cmd=cmd, src='[feature_pim6]', dest='pim[enabled_pim6]', address_family='ipv6', pip_str='feature') # get vrfs for usage on attribtues of specific vrf maker.add_leaf(cmd=cmd, src='[vrf]', dest='v4_vrfs_list', pip_str='vrf', address_family='ipv4', action=lambda x: list(x.keys())) maker.add_leaf(cmd=cmd, src='[vrf]', dest='v6_vrfs_list', pip_str='vrf', address_family='ipv6', action=lambda x: list(x.keys())) # A workaround to pass the context as in maker it expects Context.cli # not just a string 'cli. maker.context_manager[cmd] = Context.cli maker.make() maker.v4_vrfs_list = getattr(maker, 'v4_vrfs_list', []) maker.v4_vrfs_list.append('default') maker.v4_vrfs_list = set(maker.v4_vrfs_list) maker.v6_vrfs_list = getattr(maker, 'v6_vrfs_list', []) maker.v6_vrfs_list.append('default') maker.v6_vrfs_list = set(maker.v6_vrfs_list) v4_map = map(lambda x: (x, 'ipv4'), maker.v4_vrfs_list) v6_map = map(lambda x: (x, 'ipv6'), maker.v6_vrfs_list) for vrf, af in list(v4_map) + list(v6_map): # only support on ipv4 # auto-rp if af == 'ipv4': atuo_an_src = '[vrf][{vrf}][address_family][ipv4][rp][autorp][send_rp_announce]'.format( vrf=vrf) atuo_an_dest = 'pim[vrf_attr][{vrf}][address_family_attr][ipv4]'.format( vrf=vrf) for src_key, dest_key in { 'interface': 'send_rp_announce_intf', 'group': 'send_rp_announce_rp_group', 'group_list': 'send_rp_announce_group_list', 'route_map': 'send_rp_announce_route_map', 'prefix_list': 'send_rp_announce_prefix_list', 'interval': 'send_rp_announce_interval', 'scope': 'send_rp_announce_scope', 'bidir': 'send_rp_announce_bidir', }.items(): maker.add_leaf(cmd=cmd, src=atuo_an_src + '[%s]' % src_key, dest=atuo_an_dest + '[%s]' % dest_key, pip_str='send-rp-announce', vrf=vrf, address_family='ipv4') maker.make() if kwargs.get('attributes', None): kwargs['attributes'].remove('v4_vrfs_list') kwargs['attributes'].remove('v6_vrfs_list') # Take a copy of the object dictionary if not hasattr(maker, 'pim'): maker.pim = {} new_pim = maker.pim # List of mapped conf objects conf_obj_list = [] # Main structure attributes in the conf object structure_keys = ['vrf_attr', 'address_family_attr'] # Instiantiate a PIM conf object conf_obj = self() # Pass the class method not the instnace. maker.dict_to_obj(conf=conf_obj,\ struct=structure_keys,\ struct_to_map=new_pim) conf_obj_list.append(conf_obj) # List of mapped conf objects return conf_obj_list
class IPv4Addr(ConfigurableBase): @property def testbed(self): return self.device.testbed @property def device(self): return self._device() # ipv4 ipv4 = managedattribute(name='ipv4', default=None, type=(None, IPv4Address, managedattribute.test_istype(str)), doc='IP address') # ipv4_secondary ipv4_secondary = managedattribute( name='ipv4_secondary', default=None, type=(None, managedattribute.test_istype(bool)), doc='Make this IP address a secondary address') # prefix_length prefix_length = managedattribute(name='prefix_length', default=None, type=(None, managedattribute.test_istype(str)), doc='IP subnet mask') # route_tag route_tag = managedattribute( name='route_tag', default=None, type=(None, managedattribute.test_istype(str)), doc='URIB route tag value for local/direct routes') # secondary_vrf secondary_vrf = managedattribute( name='secondary_vrf', default=None, type=(None, managedattribute.test_istype(str)), doc='Assign the secondary address to a VRF table') # ip redirect redirect = managedattribute(name='redirect', default=None, type=(None, managedattribute.test_istype(bool)), doc='Assign the redirect attribute') # Overload __eq__ def __eq__(self, other): if not isinstance(other, IPv4Addr): return False return (self.ipv4, self.ipv4_secondary, self.prefix_length, self.route_tag, self.secondary_vrf, self.device) == \ (other.ipv4, other.ipv4_secondary, other.prefix_length, other.route_tag, other.secondary_vrf, other.device) # Overload __lt__ def __lt__(self, other): if not isinstance(other, IPv4Addr): return NotImplemented("Cannot compare '{s}' to a '{o}'".format( s=type(self), o=type(other))) if self.ipv4 and other.ipv4: # compare v4 addresses if both v4 return self.ipv4 < other.ipv4 # Overload __hash__ def __hash__(self): return hash((self.ipv4, self.ipv4_secondary, self.prefix_length, self.route_tag, self.secondary_vrf, self.device)) # Overload __repr__ def __repr__(self): if self.ipv4: return '%s object at 0x%x with ip address %s/%s' % ( self.__class__.__name__, id(self), self.ipv4, self.prefix_length) def __init__(self, device, *args, **kwargs): self._device = weakref.ref(device) super().__init__(*args, **kwargs)
class RoutePolicyAttributes(object): custom_config_cli = managedattribute( name='custom_config_cli', finit=str, type=managedattribute.test_istype(str)) conditions = managedattribute( name='conditions', finit=list, # Cyclic dependency -- set later #type=managedattribute.test_list_of(( # managedattribute.test_isinstance(RoutePolicyCondition), #)), ) set_label_index = managedattribute( name='label_index', default=None, type=(None, managedattribute.test_istype(int)), doc='The "set label-index" option') set_community = managedattribute( name='set_community', default=None, type=(None, managedattribute.test_istype(CommunitySet), managedattribute.test_istype(list)), doc='The "set community" option') set_nexthop = managedattribute( name='nexthop', default=None, type=(None, ip_address), doc='The "set next-hop" option') pass_on = managedattribute( name='pass_on', default=None, type=(None, managedattribute.test_istype(bool)), doc='The "pass" option: Pass this route for further processing') drop_on = managedattribute( name='drop_on', default=None, type=(None, managedattribute.test_istype(bool)), doc='The "drop" option: Reject this route with no further processing') # ==== Statement section =================== policy_definition = managedattribute( name='policy_definition', default=None, type=(None, managedattribute.test_istype(str)), doc='The route-policy name') statement_name = managedattribute( name='statement_name', default=None, type=(None, managedattribute.test_istype(str), managedattribute.test_istype(int)), doc='The route-policy statement name') description = managedattribute( name='description', default=None, type=(None, managedattribute.test_istype(str))) class ROUTE_DISPOSITION(Enum): permit = 'permit' deny = 'deny' route_disposition = managedattribute( name='route_disposition', default='permit', type=(None, ROUTE_DISPOSITION), doc='Route Disposition Enum value') match_med_eq = managedattribute( name='match_med_eq', default=None, type=(None, managedattribute.test_istype(int))) match_nexthop_in = managedattribute( name='match_nexthop_in', default=None, type=(None, managedattribute.test_istype(str))) match_nexthop_in_v6 = managedattribute( name='match_nexthop_in_v6', default=None, type=(None, managedattribute.test_istype(str))) match_local_pref_eq = managedattribute( name='match_local_pref_eq', default=None, type=(None, managedattribute.test_istype(int))) class MATCH_ROUTE_TYPE(Enum): internal = 'internal' external = 'external' match_route_type = managedattribute( name='match_route_type', default=None, type=(None, MATCH_ROUTE_TYPE)) match_community_list = managedattribute( name='match_community_list', default=None, type=(None, managedattribute.test_istype(str))) match_ext_community_list = managedattribute( name='match_ext_community_list', default=None, type=(None, managedattribute.test_istype(str))) # ==== XR Specific =================== class MATCH_ORIGIN_EQ(Enum): igp = 'igp' egp = 'egp' incomplete = 'incomplete' match_origin_eq = managedattribute( name='match_origin_eq', default=None, type=(None, MATCH_ORIGIN_EQ)) class MATCH_EXT_COMMUNITY_LIST_TYPE(Enum): soo = 'soo' rt = 'rt' match_ext_community_list_type = managedattribute( name='match_ext_community_list_type ', default=None, type=(None, MATCH_EXT_COMMUNITY_LIST_TYPE)) match_as_path_length = managedattribute( name='match_as_path_length', default=None, type=(None, managedattribute.test_istype(int))) class MATCH_AS_PATH_LENGTH_OPER(Enum): eq = 'eq' ge = 'ge' le = 'le' match_as_path_length_oper = managedattribute( name='match_as_path_length_oper', default=None, type=(None, MATCH_AS_PATH_LENGTH_OPER)) area_eq = managedattribute( name='area_eq', default=None, type=(None, managedattribute.test_istype(int), IPv4Address)) class SET_EXT_COMMUNITY_DELETE_TYPE(Enum): soo = 'soo' rt = 'rt' set_ext_community_delete_type = managedattribute( name='set_ext_community_delete_type ', default=None, type=(None, SET_EXT_COMMUNITY_DELETE_TYPE)) class ACTIONS(Enum): rppass = '******' done = 'done' drop = 'drop' actions = managedattribute( name='actions', default=None, type=(None, ACTIONS)) # ======================= match_as_path_list = managedattribute( name='match_as_path_list', default=None, type=(None, managedattribute.test_istype(str))) class MATCH_LEVEL_EQ(Enum): level_1 = 'level-1' level_2 = 'level-2' level_1_2 = 'level-1-2' match_level_eq = managedattribute( name='match_level_eq', default=None, type=(None, MATCH_LEVEL_EQ)) match_interface = managedattribute( name='match_interface', default=None, type=(None, managedattribute.test_istype(str), Interface)) match_prefix_list = managedattribute( name='match_prefix_list', default=None, type=(None, managedattribute.test_istype(str))) match_prefix_list_v6 = managedattribute( name='match_prefix_list_v6', default=None, type=(None, managedattribute.test_istype(str))) match_tag_list = managedattribute( name='match_tag_list', default=None, type=(None, managedattribute.test_istype(str))) class SET_ROUTE_ORIGIN(Enum): igp = 'igp' egp = 'egp' incomplete = 'incomplete' set_route_origin = managedattribute( name='set_route_origin', default=None, type=(None, SET_ROUTE_ORIGIN)) set_local_pref = managedattribute( name='set_local_pref', default=None, type=(None, managedattribute.test_istype(int))) set_next_hop = managedattribute( name='set_next_hop', default=None, type=(None, managedattribute.test_istype(str), IPv4Address)) set_next_hop_v6 = managedattribute( name='set_next_hop_v6', default=None, type=(None, managedattribute.test_istype(str), IPv6Address)) set_next_hop_self = managedattribute( name='set_next_hop_self', default=None, type=(None, managedattribute.test_istype(bool))) set_med = managedattribute( name='set_med', default=None, type=(None, managedattribute.test_istype(int), managedattribute.test_istype(str))) set_as_path_prepend = managedattribute( name='set_as_path_prepend', default=None, type=(None, managedattribute.test_istype(str))) set_as_path_prepend_n = managedattribute( name='set_as_path_prepend_n', default=None, type=(None, managedattribute.test_istype(int))) set_community_no_export = managedattribute( name='set_community_no_export', default=None, type=(None, managedattribute.test_istype(bool))) set_community_no_advertise = managedattribute( name='set_community_no_advertise', default=None, type=(None, managedattribute.test_istype(bool))) set_community_additive = managedattribute( name='set_community_additive', default=None, type=(None, managedattribute.test_istype(bool))) set_community_delete = managedattribute( name='set_community_delete', default=None, type=(None, managedattribute.test_istype(str))) set_ext_community_rt = managedattribute( name='set_ext_community_rt', default=None, type=(None, managedattribute.test_istype(list))) set_ext_community_rt_additive = managedattribute( name='set_ext_community_rt_additive', default=None, type=(None, managedattribute.test_istype(bool))) set_ext_community_soo = managedattribute( name='set_ext_community_soo', default=None, type=(None, managedattribute.test_istype(str))) set_ext_community_soo_additive = managedattribute( name='set_ext_community_soo_additive', default=None, type=(None, managedattribute.test_istype(bool))) set_ext_community_vpn = managedattribute( name='set_ext_community_vpn', default=None, type=(None, managedattribute.test_istype(str))) set_ext_community_vpn_additive = managedattribute( name='set_ext_community_vpn_additive', default=None, type=(None, managedattribute.test_istype(bool))) set_ext_community_delete = managedattribute( name='set_ext_community_delete', default=None, type=(None, managedattribute.test_istype(str))) class SET_LEVEL(Enum): level_1 = 'level-1' level_2 = 'level-2' level_1_2 = 'level-1-2' set_level = managedattribute( name='set_level', default=None, type=(None, SET_LEVEL)) class SET_METRIC_TYPE(Enum): internal = 'internal' external = 'external' set_metric_type = managedattribute( name='set_metric_type', default=None, type=(None, SET_METRIC_TYPE)) set_metric = managedattribute( name='set_metric', default=None, type=(None, managedattribute.test_istype(int))) class SET_OSPF_METRIC_TYPE(Enum): type_1 = 'type-1' type_2 = 'type-2' set_ospf_metric_type = managedattribute( name='set_ospf_metric_type', default=None, type=(None, SET_OSPF_METRIC_TYPE)) set_ospf_metric = managedattribute( name='set_ospf_metric', default=None, type=(None, managedattribute.test_istype(int))) set_tag = managedattribute( name='set_tag', default=None, type=(None, managedattribute.test_istype(int), IPv4Address)) set_weight = managedattribute( name='set_weight', default=None, type=(None, managedattribute.test_istype(int))) def rpl_apply_attributes(self, obj, *, setattr=setattr, getattr=getattr): '''Apply RoutePolicyAttributes rules to an object. It is best to apply device-specific rules from a RoutePolicy instead:: rpl.device_attr[device].rpl_apply_attributes(obj, ...) Returns: True: pass -- explicit False: drop None: undetermined ''' implicit_pass_on = None if self.custom_config_cli: setattr(obj, 'custom_config_cli', self.custom_config_cli) implicit_pass_on = True for cond in self.conditions: if cond.rpl_test_condition(obj, getattr=getattr): sub_pass_on = cond.if_attr.rpl_apply_attributes(obj, setattr=setattr, getattr=getattr) if sub_pass_on is not None: if sub_pass_on: implicit_pass_on = True else: return False else: sub_pass_on = cond.else_attr.rpl_apply_attributes(obj, setattr=setattr, getattr=getattr) if sub_pass_on is not None: if sub_pass_on: implicit_pass_on = True else: return False if self.set_nexthop is not None: setattr(obj, 'nexthop', self.set_nexthop) implicit_pass_on = True if self.set_label_index is not None: setattr(obj, 'label_index', self.set_label_index) implicit_pass_on = True if self.set_community is not None: setattr(obj, 'community', self.set_community) implicit_pass_on = True if self.pass_on: assert not self.drop_on setattr(obj, 'pass', True) return True elif self.drop_on: setattr(obj, 'drop', True) return False else: return implicit_pass_on
class IPv6Addr(ConfigurableBase): @property def testbed(self): return self.device.testbed @property def device(self): return self._device() # ipv6 ipv6 = managedattribute(name='ipv6', default=None, type=(None, IPv6Address), doc='IPv6 address') # ipv6_prefix_length ipv6_prefix_length = managedattribute( name='ipv6_prefix_length', default=None, type=(None, managedattribute.test_istype(str)), doc='IPv6 subnet mask') # ipv6_anycast ipv6_anycast = managedattribute(name='ipv6_anycast', default=None, type=(None, managedattribute.test_istype(bool)), doc='Configure as an anycast') # ipv6_eui_64 ipv6_eui_64 = managedattribute(name='ipv6_eui_64', default=None, type=(None, managedattribute.test_istype(bool)), doc='Use eui-64 interface identifier') # ipv6_route_tag ipv6_route_tag = managedattribute( name='ipv6_route_tag', default=None, type=(None, managedattribute.test_istype(bool)), doc='Route-tag to be associated with this address') # ipv6 redirect redirect = managedattribute(name='redirect', default=None, type=(None, managedattribute.test_istype(bool)), doc='Assign the v6 redirect attribute') # Overload __eq__ def __eq__(self, other): if not isinstance(other, IPv6Addr): return False return (self.ipv6, self.ipv6_prefix_length, self.ipv6_anycast, self.ipv6_eui_64, self.ipv6_route_tag, self.device) == \ (other.ipv6, other.ipv6_prefix_length, other.ipv6_anycast, other.ipv6_eui_64, other.ipv6_route_tag, other.device) # Overload __lt__ def __lt__(self, other): if not isinstance(other, IPv6Addr): return NotImplemented("Cannot compare '{s}' to a '{o}'"\ .format(s=type(self), o=type(other))) if self.ipv6 and other.ipv6: # compare v6 addresses if both v6 return self.ipv6 < other.ipv6 # Overload __hash__ def __hash__(self): return hash((self.ipv6, self.ipv6_prefix_length, self.ipv6_anycast, self.ipv6_eui_64, self.ipv6_route_tag, self.device)) # Overload __repr__ def __repr__(self): if self.ipv6: return '%s object at 0x%x with ip address %s/%s' % ( self.__class__.__name__, id(self), self.ipv6, self.ipv6_prefix_length) def __init__(self, device, *args, **kwargs): self._device = weakref.ref(device) super().__init__(*args, **kwargs)
class RoutePolicy(RoutePolicyAttributes, RoutePolicyMixin, DeviceFeature): Condition = RoutePolicyCondition name = managedattribute( name='name', type=managedattribute.test_istype(str)) def rpl_apply_attributes(self, obj, **kwargs): '''Apply RoutePolicyAttributes rules to an object. It is best to apply device-specific rules using instead:: rpl.device_attr[device].rpl_apply_attributes(obj, ...) Returns: True: pass -- implicit or explicit False: drop ''' pass_on = super().rpl_apply_attributes(obj, **kwargs) return False if pass_on is None else pass_on custom_unconfig_cli = managedattribute( name='custom_unconfig_cli', finit=str, type=managedattribute.test_istype(str)) class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): def rpl_apply_attributes(self, obj, **kwargs): '''Apply device-specific RoutePolicyAttributes rules to an object. Returns: True: pass -- implicit or explicit False: drop ''' pass_on = RoutePolicyAttributes.rpl_apply_attributes(self, obj, **kwargs) return False if pass_on is None else pass_on class StatementAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.statement_name = key super().__init__(parent) statement_attr = managedattribute( name='statement_attr', read_only=True, doc=StatementAttributes.__doc__) @statement_attr.initter def statement_attr(self): return SubAttributesDict(self.StatementAttributes, parent=self) 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, name=None, policy_definition=None, *args, **kwargs): if name: self.name = name if policy_definition: self.policy_definition = policy_definition # Make sure at least one was populated: if not name and not policy_definition: raise TypeError("__init__() requires either 'name' or " "'policy_definition' to be provided") if 'route_disposition' in kwargs: self.route_disposition = kwargs['route_disposition'] 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) cfgs = {key: value for key, value in cfgs.items() if value} 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) cfgs = {key: value for key, value in cfgs.items() if value} if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs
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
class Rsvp(DeviceFeature, LinkFeature): @property def interfaces(self): interfaces = set() interfaces.update(*[link.interfaces for link in self.links]) return frozenset(interfaces) @property def controllers(self): controllers = set() # TODO return frozenset(controllers) # Top level attributes auth_keysrc_keychain = managedattribute( name='auth_keysrc_keychain', default=None, type=(None, managedattribute.test_istype(str))) auth_lifetime = managedattribute(name='auth_lifetime', default=None, type=(None, managedattribute.test_istype(int))) auth_window_size = managedattribute( name='auth_window_size', default=None, type=(None, managedattribute.test_istype(int))) auth_retransmit = managedattribute( name='auth_retransmit', default=None, type=(None, managedattribute.test_istype(int))) log_events_issu = managedattribute( name='log_events_issu', default=None, type=(None, managedattribute.test_istype(bool))) log_events_nsr = managedattribute( name='log_events_nsr', default=None, type=(None, managedattribute.test_istype(bool))) sig_checksum = managedattribute(name='sig_checksum', default=None, type=(None, managedattribute.test_istype(bool))) sig_event_per_pulse = managedattribute( name='sig_event_per_pulse', default=None, type=(None, managedattribute.test_istype(int))) sig_gr = managedattribute(name='sig_gr', default=None, type=(None, managedattribute.test_istype(bool))) sig_gr_mode = managedattribute(name='sig_gr_mode', default='full', type=(None, managedattribute.test_istype(str))) sig_gr_recov_time = managedattribute( name='sig_gr_recov_time', default=None, type=(None, managedattribute.test_istype(int))) sig_gr_restart_time = managedattribute( name='sig_gr_restart_time', default=None, type=(None, managedattribute.test_istype(int))) sig_hello_gr_refresh_interval = managedattribute( name='sig_hello_gr_refresh_interval', default=None, type=(None, managedattribute.test_istype(int))) sig_hello_gr_refresh_misses = managedattribute( name='sig_hello_gr_refresh_misses', default=None, type=(None, managedattribute.test_istype(int))) sig_message_bundle = managedattribute( name='sig_message_bundle', default=None, type=(None, managedattribute.test_istype(bool))) sig_outofband_vrf = managedattribute( name='sig_outofband_vrf', default=None, type=(None, managedattribute.test_isinstance(Vrf))) sig_patherr_state_removal = managedattribute( name='sig_patherr_state_removal', default=None, type=(None, managedattribute.test_istype(bool))) sig_prefixfilt_acl = managedattribute( name='sig_prefixfilt_acl', default=None, type=(None, managedattribute.test_isinstance(AccessList))) class PrefixFilteringAction(Enum): drop = 'drop' sig_prefixfilt_defdenyaction = managedattribute( name='sig_prefixfilt_defdenyaction', default=None, type=(None, PrefixFilteringAction)) # Per-interface attributes sig_refresh_outofband_interval = managedattribute( name='sig_refresh_outofband_interval', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_outofband_missed = managedattribute( name='sig_refresh_outofband_missed', default=None, type=(None, managedattribute.test_istype(int))) sig_dscp = managedattribute(name='sig_dscp', default=None, type=(None, managedattribute.test_istype(int))) sig_hello_gr_intfbased = managedattribute( name='sig_hello_gr_intfbased', default=None, type=(None, managedattribute.test_istype(bool))) sig_rate_limit = managedattribute(name='sig_rate_limit', default=None, type=(None, managedattribute.test_istype( (bool, int)))) sig_rate_limit_interval = managedattribute( name='sig_rate_limit_interval', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_interval = managedattribute( name='sig_refresh_interval', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_missed = managedattribute( name='sig_refresh_missed', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_reduction_bundle_maxsize = managedattribute( name='sig_refresh_reduction_bundle_maxsize', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_reduction = managedattribute( name='sig_refresh_reduction', default=None, type=(None, managedattribute.test_istype(bool))) sig_refresh_reduction_reliable_ack_holdtime = managedattribute( name='sig_refresh_reduction_reliable_ack_holdtime', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_reduction_reliable_ack_maxsize = managedattribute( name='sig_refresh_reduction_reliable_ack_maxsize', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_reduction_reliable_retransmit_time = managedattribute( name='sig_refresh_reduction_reliable_retransmit_time', default=None, type=(None, managedattribute.test_istype(int))) sig_refresh_reduction_reliable_summary_refresh = managedattribute( name='sig_refresh_reduction_reliable_summary_refresh', default=None, type=(None, managedattribute.test_istype(bool))) sig_refresh_reduction_summary_maxsize = managedattribute( name='sig_refresh_reduction_summary_maxsize', default=None, type=(None, managedattribute.test_istype(int))) class BwUnit(Enum): kbps = 'kbps' mbps = 'mbps' gbps = 'gbps' enable_default_bw = managedattribute( name='enable_default_bw', default=None, type=(None, managedattribute.test_istype(bool))) class RdmBwCliStyle(Enum): unnamed_subpool = 'unnamed_subpool' bc0_bc1 = 'bc0_bc1' global_subpool = 'global_subpool' rdm_bw_cli_rdm_kw = managedattribute( name='rdm_bw_cli_rdm_kw', default=True, type=managedattribute.test_istype(bool)) rdm_bw_cli_style = managedattribute(name='rdm_bw_cli_style', default=RdmBwCliStyle.unnamed_subpool, type=RdmBwCliStyle) rdm_bw_percentage = managedattribute( name='rdm_bw_percentage', default=False, type=managedattribute.test_istype(bool)) rdm_bw_total = managedattribute(name='rdm_bw_total', default=20000, type=(None, managedattribute.test_istype(int))) rdm_bw_total_unit = managedattribute(name='rdm_bw_total_unit', default=None, type=(None, BwUnit)) rdm_bw_largest = managedattribute(name='rdm_bw_largest', default=20000, type=(None, managedattribute.test_istype(int))) rdm_bw_largest_unit = managedattribute(name='rdm_bw_largest_unit', default=None, type=(None, BwUnit)) rdm_bw_subpool = managedattribute(name='rdm_bw_subpool', default=None, type=(None, managedattribute.test_istype(int))) rdm_bw_subpool_unit = managedattribute(name='rdm_bw_subpool_unit', default=None, type=(None, BwUnit)) mam_bw_percentage = managedattribute( name='mam_bw_percentage', default=None, type=(None, managedattribute.test_istype(bool))) mam_bw_max_reservable = managedattribute( name='mam_bw_max_reservable', default=None, type=(None, managedattribute.test_istype(bool))) mam_bw_total = managedattribute(name='mam_bw_total', default=None, type=(None, managedattribute.test_istype(int))) mam_bw_total_unit = managedattribute(name='mam_bw_total_unit', default=None, type=(None, BwUnit)) mam_bw_largest = managedattribute(name='mam_bw_largest', default=None, type=(None, managedattribute.test_istype(int))) mam_bw_largest_unit = managedattribute(name='mam_bw_largest_unit', default=None, type=(None, BwUnit)) mam_bw_bc0 = managedattribute(name='mam_bw_bc0', default=None, type=(None, managedattribute.test_istype(int))) mam_bw_bc0_unit = managedattribute(name='mam_bw_bc0_unit', default=None, type=(None, BwUnit)) mam_bw_bc1 = managedattribute(name='mam_bw_bc1', default=None, type=(None, managedattribute.test_istype(int))) mam_bw_bc1_unit = managedattribute(name='mam_bw_bc1_unit', default=None, type=(None, BwUnit)) class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): enabled_feature = managedattribute( name='enabled_feature', default=False, type=managedattribute.test_istype(bool), doc='''Argument to control 'mpls traffic-engineering' CLI''') @property def interfaces(self): device = self.device interfaces = set(self.parent.interfaces) #interfaces.update(*[link.interfaces for link in self.parent.links]) interfaces = {intf for intf in interfaces if intf.device is device} return frozenset(interfaces) @property def controllers(self): # TODO device = self.device controllers = set(self.parent.controllers) #controllers.update(*[link.interfaces for link in self.parent.links]) controllers = { intf for intf in controllers if intf.device is device } return frozenset(controllers) neighbors = managedattribute( name='neighbors', finit=typedset(IPv4NeighborSubAttributes).copy, type=typedset(IPv4NeighborSubAttributes)._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 InterfaceAttributes( genie.conf.base.attributes.InterfaceSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) 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(IPv4NeighborSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) 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 ControllerAttributes( genie.conf.base.attributes.InterfaceSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) controller_attr = managedattribute(name='controller_attr', read_only=True, doc=ControllerAttributes.__doc__) @controller_attr.initter def controller_attr(self): return SubAttributesDict(self.ControllerAttributes, parent=self) def __init__(self, *args, **kwargs): super().__init__(*args, **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 __init__(self, pid=None, *args, **kwargs): super().__init__(*args, **kwargs) def build_config(self, links=None, apply=True, attributes=None, **kwargs): '''Rsvp top build config''' attributes = AttributesHelper(self, attributes) cfgs = {} if links is None: devices = self.devices else: devices = set().union(*[link.devices for link in links]) 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, links=None, apply=True, attributes=None, **kwargs): '''Rsvp top build unconfig''' attributes = AttributesHelper(self, attributes) cfgs = {} if links is None: devices = self.devices else: devices = set().union(*[link.devices for link in links]) 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 AreaDefaultCost(ConfigurableBase): @property def testbed(self): return self.device.testbed @property def device(self): return self._device() # ========================================================================== # MANAGED ATTRIBUTES # ========================================================================== # +- DeviceAttributes # +- VrfAttributes # +- AddressFamilyAttributes # af_area_id af_area_id = managedattribute(name='af_area_id', default=None, type=(None, managedattribute.test_istype(str))) # area_def_cost area_def_cost = managedattribute(name='area_def_cost', default=None, type=(None, managedattribute.test_istype(int))) # ========================================================================== # Overload __eq__ def __eq__(self, other): if not isinstance(other, AreaDefaultCost): raise NotImplemented return (self.af_area_id, self.area_def_cost, self.device) == \ (other.af_area_id, other.area_def_cost, other.device) # Overload __lt__ def __lt__(self, other): if not isinstance(other, AreaDefaultCost): raise NotImplemented("Cannot compare '{s}' to a '{o}'".format( s=type(self), o=type(other))) return (self.af_area_id, self.area_def_cost, self.device) < \ (other.af_area_id, other.area_def_cost, other.device) # Overload __hash__ def __hash__(self): return hash((self.af_area_id, self.area_def_cost, self.device)) # Overload __repr__ def __repr__(self): return '%s object at 0x%x' % (self.__class__.__name__, id(self)) def __init__(self, device, *args, **kwargs): self._device = weakref.ref(device) super().__init__(*args, **kwargs)
class Acl(DeviceFeature): # device attributes acl_type = managedattribute(name='acl_type', default=None, type=(None, managedattribute.test_in([ 'ipv4-acl-type', 'ipv6-acl-type', 'eth-acl-type' ]))) acl_name = managedattribute(name='acl_name', default=None, type=(None, managedattribute.test_istype(str))) seq = managedattribute(name='seq', default=None, type=(None, managedattribute.test_istype(str))) actions_forwarding = managedattribute( name='actions_forwarding', default=None, type=(None, managedattribute.test_istype(str))) protocol = managedattribute(name='protocol', default=None, type=(None, managedattribute.test_istype(str))) src = managedattribute(name='src', default=None, type=(None, managedattribute.test_istype(str))) src_operator = managedattribute(name='src_operator', default=None, type=(None, managedattribute.test_istype(str))) src_port = managedattribute(name='src_port', default=None, type=(None, managedattribute.test_istype(str))) dst = managedattribute(name='dst', default=None, type=(None, managedattribute.test_istype(str))) dst_operator = managedattribute(name='dst_operator', default=None, type=(None, managedattribute.test_istype(str))) dst_port = managedattribute(name='dst_port', default=None, type=(None, managedattribute.test_istype(str), managedattribute.test_istype(str))) option = managedattribute(name='option', default=None, type=(None, managedattribute.test_istype(str))) precedence = managedattribute(name='precedence', default=None, type=(None, managedattribute.test_istype(str))) dscp = managedattribute(name='dscp', default=None, type=(None, managedattribute.test_istype(str))) established = managedattribute(name='established', default=None, type=(None, managedattribute.test_istype(bool))) actions_logging = managedattribute( name='actions_logging', default=None, type=(None, managedattribute.test_istype(str))) ttl = managedattribute(name='ttl', default=None, type=(None, managedattribute.test_istype(str))) ttl_operator = managedattribute(name='ttl_operator', default=None, type=(None, managedattribute.test_istype(str))) ether_type = managedattribute(name='ether_type', default=None, type=(None, managedattribute.test_istype(str))) interface_id = managedattribute(name='interface_id', default=None, type=(None, managedattribute.test_istype(str))) if_in = managedattribute(name='if_in', default=None, type=(None, managedattribute.test_istype(bool))) if_out = managedattribute(name='if_out', default=None, type=(None, managedattribute.test_istype(bool))) class DeviceAttributes(DeviceSubAttributes): class AclAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.acl_name = key super().__init__(parent) class InterfaceAttributes(InterfaceSubAttributes): def __init__(self, parent, key): self.interface_id = 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 AceAttributes(KeyedSubAttributes): def __init__(self, parent, key): self.seq = key super().__init__(parent) ace_attr = managedattribute(name='ace_attr', read_only=True, doc=AceAttributes.__doc__) @ace_attr.initter def ace_attr(self): return SubAttributesDict(self.AceAttributes, parent=self) acl_attr = managedattribute(name='acl_attr', read_only=True, doc=AclAttributes.__doc__) @acl_attr.initter def acl_attr(self): return SubAttributesDict(self.AclAttributes, parent=self) 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 Lisp(Routing, DeviceFeature): def __init__(self, **kwargs): super().__init__(**kwargs) router_lisp_id = managedattribute(name="router_lisp_id", default="", type=(None, managedattribute.test_istype(str))) site_id = managedattribute(name="site_id", default=None, type=(None, managedattribute.test_istype(str))) security = managedattribute(name="security", default=None, type=(None, managedattribute.test_istype(str))) auto_discover_rlocs = managedattribute( name="auto_discover_rlocs", default=None, type=(None, managedattribute.test_istype(bool))) encapsulation = managedattribute( name="encapsulation", default=None, type=(None, managedattribute.test_istype(Encapsulation))) service = managedattribute( name="service", default=None, type=(None, managedattribute.test_istype(ServiceType))) dynamic_eid_name = managedattribute( name="dynamic_eid_name", default=None, type=(None, managedattribute.test_istype(str))) eid_records = managedattribute(name="eid_records", default=None, type=( None, managedattribute.test_istype(list), )) eid_table = managedattribute(name="eid_table", default=None, type=(None, managedattribute.test_istype(str))) itr_enabled = managedattribute(name="itr_enabled", default=None, type=(None, managedattribute.test_istype(bool))) # TODO: make itr_values a namedtuple type itr_values = managedattribute(name="itr_values", default=None, type=(None, managedattribute.test_istype(list))) etr_enabled = managedattribute(name="etr_enabled", default=None, type=(None, managedattribute.test_istype(bool))) # TODO: make etr_values a namedtuple type etr_values = managedattribute(name="etr_values", default=None, type=(None, managedattribute.test_istype(list))) eth_db_mapping = managedattribute( name="eth_db_map", default=None, type=(None, managedattribute.test_istype(list))) ipv4_db_map = managedattribute(name="ipv4_db_map", default=None, type=(None, managedattribute.test_istype(list))) ipv6_db_map = managedattribute(name="ipv6_db_map", default=None, type=(None, managedattribute.test_istype(list))) rloc_value = managedattribute(name="rloc_value", default=None, type=(None, managedattribute.test_istype(str))) map_request_source = managedattribute( name="map_request_source", default=None, type=(None, managedattribute.test_istype(str))) use_petr = managedattribute(name="use_petr", default=None, type=(None, managedattribute.test_istype(str))) map_cache_persistence_interval = managedattribute( name="map_cache_persistence_interval", default=0, type=(None, managedattribute.test_istype(int))) site_registrations = managedattribute( name="site_registrations", default=None, type=(None, managedattribute.test_istype(int))) authentication_key = managedattribute( name="authentication_key", default=None, type=(None, managedattribute.test_istype(str))) test_attrib = managedattribute(name="test_attrib", default=None, type=(None, managedattribute.test_istype(str))) map_resolver_enabled = managedattribute( name="map_resolver_enabled", default=None, type=(None, managedattribute.test_istype(bool))) map_cache_limit = managedattribute( name="map_cache_limit", default=None, type=(None, managedattribute.test_istype(int))) map_server_enabled = managedattribute( name="map_server_enabled", default=None, type=(None, managedattribute.test_istype(bool))) map_resolver = managedattribute(name="map_resolver", default=None, type=(None, managedattribute.test_istype(str))) map_server = managedattribute(name="map_server", default=None, type=(None, managedattribute.test_istype(str))) locator_table = managedattribute(name="locator_table", default=None, type=(None, managedattribute.test_istype(str))) control_packet = managedattribute(name="control_packet", default=None, type=(None, managedattribute.test_istype(int))) ddt = managedattribute(name="ddt", default=None, type=(None, managedattribute.test_istype(str))) decapsulation = managedattribute(name="decapsulation", default=None, type=(None, managedattribute.test_istype(str))) default = managedattribute(name="default", default=None, type=(None, managedattribute.test_istype(str))) disable_ttl_propagate = managedattribute( name="disable_ttl_progagate", default=None, type=(None, managedattribute.test_istype(bool))) loc_reach_algorithm = managedattribute( name="loc_reach_algorithm", default=None, type=(None, managedattribute.test_istype(str))) locator = managedattribute(name="locator", default=None, type=(None, managedattribute.test_istype(str))) locator_down = managedattribute(name="locator_down", default=None, type=(None, managedattribute.test_istype(str))) rloc_prefix = managedattribute(name="rloc_prefix", default=None, type=(None, managedattribute.test_istype(str))) rtr_locator_set = managedattribute( name="rtr_locater_set", default=None, type=(None, managedattribute.test_istype(str))) map_request = managedattribute(name="map_request", default=None, type=(None, managedattribute.test_istype(str))) class DeviceAttributes(DeviceSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) class VrfAttributes(VrfSubAttributes): def __init__(self, **kwargs): super().__init__(**kwargs) class ServiceAttributes(KeyedSubAttributes): """Block for service attributes""" def __init__(self, parent, key): self.service_name = key super().__init__(parent=parent) service_attr = managedattribute(name="service_attr", read_only=False, doc=ServiceAttributes.__doc__) @service_attr.initter def service_attr(self): return SubAttributesDict(self.ServiceAttributes, parent=self) class LocatorScopeAttributes(KeyedSubAttributes): """Block for locator-scopy attributes""" def __init__(self, parent, key): self.locator_scope_name = key super().__init__(parent=parent) locator_scope_attr = managedattribute( name="locator_scope_attr", read_only=False, doc=LocatorScopeAttributes.__doc__) @locator_scope_attr.initter def locator_scope_attr(self): return SubAttributesDict(self.LocatorScopeAttributes, parent=self) class DynamicEIDAttributes(KeyedSubAttributes): """Block for Dynamic EID attributes""" def __init__(self, parent, key): self.dynamic_eid_name = key super().__init__(parent=parent) dynamic_eid_attr = managedattribute(name="dynamic_eid_attr", read_only=False) @dynamic_eid_attr.initter def dynamic_eid_attr(self): return SubAttributesDict(self.DynamicEIDAttributes, parent=self) class SiteAttributes(KeyedSubAttributes): """Block for site attrs""" def __init__(self, parent, key): self.site_name = key super().__init__(parent=parent) site_attr = managedattribute(name="site_attr", read_only=False, doc=SiteAttributes.__doc__) @site_attr.initter def site_attr(self): return SubAttributesDict(self.SiteAttributes, parent=self) class LocatorSetAttributes(KeyedSubAttributes): """Block for locator-set""" def __init__(self, parent, key): self.locator_set_name = key super().__init__(parent=parent) locatorset_attr = managedattribute( name='locatorset_attr', read_only=False, doc=LocatorSetAttributes.__doc__) @locatorset_attr.initter def locatorset_attr(self): return SubAttributesDict(self.LocatorSetAttributes, parent=self) class InstanceAttributes(KeyedSubAttributes): """Block for instance attrs""" def __init__(self, parent, key): self.instance_id = key super().__init__(parent=parent) service_attr = managedattribute(name="service_attr", read_only=False) @service_attr.initter def service_attr(self): return SubAttributesDict(self.parent.ServiceAttributes, parent=self) dynamic_eid_attr = managedattribute(name="dynamic_eid_attr", read_only=False) @dynamic_eid_attr.initter def dynamic_eid_attr(self): return SubAttributesDict(self.DynamicEIDAttributes, parent=self) instance_attr = managedattribute(name="instance_attr", read_only=False, doc=InstanceAttributes.__doc__) @instance_attr.initter def instance_attr(self): return SubAttributesDict(self.InstanceAttributes, parent=self) vrf_attr = managedattribute(name='vrf_attr', read_only=False, doc=VrfAttributes.__doc__) @vrf_attr.initter def vrf_attr(self): return SubAttributesDict(self.VrfAttributes, parent=self) device_attr = managedattribute(name='device_attr', read_only=False, doc=DeviceAttributes.__doc__) @device_attr.initter def device_attr(self): return SubAttributesDict(self.DeviceAttributes, parent=self) def build_config(self, devices=None, apply=True, attributes=None): #TODO add interfaces attributes = AttributesHelper(self, attributes) cfgs = {} 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: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, apply=True, attributes=None): #TODO add interfaces attributes = AttributesHelper(self, attributes) cfgs = {} # devices = consolidate_feature_args(self, 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: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs
class Mld(Routing, DeviceFeature, InterfaceFeature): # global_max_groups global_max_groups = managedattribute( name='global_max_groups', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure global_max_groups under vrf attribute.") # enable enable = managedattribute( name='enable', default=None, type=(None, managedattribute.test_istype(bool)), doc="Configure 'ipv6 mld router' under interface.") # group_policy group_policy = managedattribute( name='group_policy', default=None, type=(None, managedattribute.test_istype(str)), doc="Configure group_policy under interface.") # immediate_leave immediate_leave = managedattribute( name='immediate_leave', default=None, type=(None, managedattribute.test_istype(bool)), doc="Configure immediate_leave under interface.") # max_groups max_groups = managedattribute(name='max_groups', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure max_groups under interface.") # query_interval query_interval = managedattribute( name='query_interval', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure query_interval under interface.") # query_max_response_time query_max_response_time = managedattribute( name='query_max_response_time', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure query_max_response_time under interface.") # robustness_variable robustness_variable = managedattribute( name='robustness_variable', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure robustness_variable.") # version version = managedattribute(name='version', default=None, type=(None, managedattribute.test_istype(int)), doc="Configure version under interface.") class DeviceAttributes(DeviceSubAttributes): class VrfAttributes(VrfSubAttributes): def __init__(self, parent, key): self.vrf_id = key super().__init__(parent, key) ssm = managedattribute( name='ssm', finit=typedset(managedattribute.test_isinstance(Ssm)).copy, type=typedset( managedattribute.test_isinstance(Ssm))._from_iterable, doc='A `set` of ssm associated objects') def add_ssm(self, ssm): self.ssm.add(ssm) def remove_ssm(self, ssm): ssm._device = None try: self.ssm.remove(ssm) except: pass class InterfaceAttributes(InterfaceSubAttributes): def __init__(self, parent, key): self.intf = key super().__init__(parent, key) groups = managedattribute( name='groups', finit=typedset( managedattribute.test_isinstance(MldGroup)).copy, type=typedset(managedattribute.test_isinstance( MldGroup))._from_iterable, doc='A `set` of MldGroup associated objects') def add_groups(self, groups): self.groups.add(groups) def remove_groups(self, groups): groups._device = None try: self.groups.remove(groups) except: pass 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) vrf_attr = managedattribute(name='vrf_attr', read_only=True, doc=VrfAttributes.__doc__) @vrf_attr.initter def vrf_attr(self): return SubAttributesDict(self.VrfAttributes, parent=self) 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 build_config(self, devices=None, apply=True, attributes=None, unconfig=False): 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', sort=True): cfgs[key] = sub.build_config(apply=False, attributes=attributes2) if apply: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, apply=True, attributes=None): 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', sort=True): cfgs[key] = sub.build_unconfig(apply=False, attributes=attributes2) if apply: for device_name, cfg in sorted(cfgs.items()): self.testbed.config_on_devices(cfg, fail_invalid=True) else: return cfgs
class EthernetInterface(PhysicalInterface): # mac_address mac_address = managedattribute( name='mac_address', default=None, type=(None, MAC)) burnin_mac_address = managedattribute( name='burnin_mac_address', default=None, type=(None, MAC)) @property def effective_mac_address(self): return self.mac_address or self.burnin_mac_address auto_negotiation = managedattribute( name='auto_negotiation', default=None, type=(None, managedattribute.test_istype(bool))) speed = managedattribute( name='speed', default=None, type=(None, int, managedattribute.test_istype(str))) duplex = managedattribute( name='duplex', default=None, type=(None, managedattribute.test_istype(str))) eth_encap_type1 = managedattribute( name='eth_encap_type1', type=(None, managedattribute.test_istype(str))) @eth_encap_type1.defaulter def eth_encap_type1(self): if self.eth_encap_val1 is not None: return "dot1q" return None eth_encap_val1 = managedattribute( name='eth_encap_val1', default=None, type=(None, managedattribute.test_istype((int, range)))) eth_encap_type2 = managedattribute( name='eth_encap_type2', type=(None, managedattribute.test_istype(str))) @eth_encap_type2.defaulter def eth_encap_type2(self): if self.eth_encap_val2 is not None: if self.eth_encap_type1 == 'dot1q': return 'second-dot1q' if self.eth_encap_type1 == 'dot1ad': return 'dot1q' return None eth_encap_val2 = managedattribute( name='eth_encap_val2', default=None, type=(None, managedattribute.test_istype((int, range)))) eth_dot1q_type = managedattribute( name='eth_dot1q_type', type=(None, managedattribute.test_istype(str))) @eth_dot1q_type.defaulter def eth_dot1q_type(self): if self.eth_dot1q_value is not None: return "native" return None eth_dot1q_value = managedattribute( name='eth_dot1q_value', default=None, type=(None, managedattribute.test_istype(str))) # port_speed class PORTSPEED(Enum): sp1 = '10' sp2 = '100' sp3 = '1000' sp4 = '10000' sp5 = '100000' sp6 = '40000' auto = 'auto' port_speed = managedattribute( name='port_speed', default=None, type=(None, PORTSPEED), doc= 'port_speed') # access_vlan access_vlan = managedattribute( name='access_vlan', default=None, type=(None, managedattribute.test_istype(str)), doc='Set access mode characteristics of the interface') # trunk_vlan trunk_vlan = managedattribute( name='trunk_vlans', default=None, type=(None, managedattribute.test_istype(str)), doc='Configure trunking parameters on an interface') # trunk_add_vlans trunk_add_vlans = managedattribute( name='trunk_add_vlans', default=None, type=(None, managedattribute.test_istype(str)), doc='Add VLANs to the current list') # trunk_remove_vlans trunk_remove_vlans = managedattribute( name='trunk_remove_vlans', default=None, type=(None, managedattribute.test_istype(str)), doc='Remove VLANs from the current list') # native_vlan native_vlan = managedattribute( name='native_vlan', default=None, type=(None, managedattribute.test_istype(str)), doc='Set trunking native characteristics when interface is in trunking mode') # auto_negotiate auto_negotiate = managedattribute( name='auto_negotiate', default=None, type=(None, managedattribute.test_istype(bool)), doc='Auto negotiate speed for speed and duplex') # duplex_mode class Duplex_Mode(Enum): full = 'full' half = 'half' duplex_mode = managedattribute( name='duplex_mode', default=None, type=(None, Duplex_Mode), doc='the port duplex mode') # flow_control_receive flow_control_receive = managedattribute( name='flow_control_receive', default=None, type=(None, managedattribute.test_istype(bool)), doc='Receive pause frames') # flow_control_send flow_control_send = managedattribute( name='flow_control_send', default=None, type=(None, managedattribute.test_istype(bool)), doc='Send pause frames') lag_bundle_id = managedattribute( name='lag_bundle_id', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_bundle_id') lag_activity = managedattribute( name='lag_activity', default=None, type=(None, managedattribute.test_in(['active','passive','on','auto','desirable'])), doc= 'lag_activity') lag_non_silent = managedattribute( name='lag_non_silent', default=None, type=(None, managedattribute.test_istype(bool)), doc= 'lag_non_silent') lag_force = managedattribute( name='lag_force', default=None, type=(None, managedattribute.test_istype(bool)), doc= 'lag_force') lag_lacp_port_priority = managedattribute( name='lag_lacp_port_priority', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_lacp_port_priority') lag_pagp_port_priority = managedattribute( name='lag_pagp_port_priority', default=None, type=(None, managedattribute.test_istype(int)), doc= 'lag_pagp_port_priority') @abc.abstractmethod def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if 'mac_address' not in kwargs: try: self.mac_address except AttributeError: pass else: if self.mac_address: self.testbed.mac_cache.reserve(self.mac_address) if 'auto_negotiation' not in kwargs: try: self.auto_negotiation except AttributeError: pass if 'speed' not in kwargs: try: self.speed except AttributeError: pass if 'duplex' not in kwargs: try: self.duplex except AttributeError: pass