Source code for pyhpecw7.features.irf

"""This module is used to configure IRF for a
``HPCOM7`` device. The ``IRFMember`` class is used
to change the IRF member numbers on the device, and
can force a reboot. The ``IRFPort`` class is used to
bind physical ports to IRF ports. ``IRFMember`` should
be used first and the ``IRFPort``.
"""

from pyhpecw7.utils.xml.lib import *
from pyhpecw7.features.interface import Interface
from pyhpecw7.features.errors import InterfaceAbsentError,\
    IRFMemberDoesntExistError


[docs]class IrfPort(object): """This class is used to get and build IRF port configurations on a ``HPCOM7`` device. Args: device (HPCOM7): connected instance of a ``pyhpecw7.comware.HPCOM7`` object. Attributes: device (HPCOM7): connected instance of a ``pyhpecw7.comware.HPCOM7`` object. """ def __init__(self, device): self.device = device def _build_iface_updown(self, iface_list, updown): """Stage commands to bring the interfaces up or down. """ for iface_name in iface_list: iface = Interface(self.device, iface_name) if not iface.iface_exists: raise InterfaceAbsentError(iface.interface_name) iface.build(stage=True, admin=updown)
[docs] def build(self, member_id, old_p1=[], old_p2=[], irf_p1=[], irf_p2=[], filename='startup.cfg', activate=True): """Stage all of the commands to configure IRF ports, including: 1. Bringing down interfaces to be removed or added 2. Binding physical ports to IRF ports 3. Bringing up interfaces to be added. 4. Saving the config. 5. (Optionally) activating the IRF port configuration. Args: member_id (string): The member ID of the switch. old_p1 (list): REQUIRED - A list of current interfaces bound to IRF port 1. old_p2 (list): REQUIRED - A list of current interfaces bound to IRF port 2. irf_p1 (list): REQUIRED - A list of desired interfaces to be bound to IRF port 1. irf_p2 (list): REQUIRED - A list of desired interfaeces to be bound to IRF port 2. filename (str): OPTIONAL - The filename in which to save the current configuration. Defaults to 'startup.cfg'. activate (bool): OPTIONAL - Whether to immediately apply the IRF port configuration. Defaults to ``True``. Note: The ``irf_p1`` and ``irf_p2`` should be the complete physical interface list for IRF port 1 and IRF port 2, respectively. Interfaces not in the list will be removed. Note: If ``old_p1`` and ``old_p2`` are not accurate, behavior is undefined. These values can be obtained from ``get_config()``. Returns: A string representation of the list of staged configurations on the device. """ updown_ifaces = [] updown_ifaces += list(set(old_p1).difference(irf_p1)) updown_ifaces += list(set(irf_p1).difference(old_p1)) updown_ifaces += list(set(old_p2).difference(irf_p2)) updown_ifaces += list(set(irf_p2).difference(old_p2)) self._build_iface_updown(set(updown_ifaces), 'down') EN = nc_element_maker() EC = config_element_maker() operation1 = None if not irf_p1: operation1 = 'remove' iface1_eles = [] for iface_name in irf_p1: iface1_eles.append(EC.Interface(EC.IfName(iface_name))) operation2 = None if not irf_p2: operation2 = 'remove' iface2_eles = [] for iface_name in irf_p2: iface2_eles.append(EC.Interface(EC.IfName(iface_name))) config = EN.config( EC.top( EC.IRF( EC.IRFPorts( EC.IRFPort( EC.MemberID(member_id), EC.Port('1'), *iface1_eles, **operation_kwarg(operation1) ), EC.IRFPort( EC.MemberID(member_id), EC.Port('2'), *iface2_eles, **operation_kwarg(operation2) ), ) ) ) ) self.device.stage_config(config, 'edit_config') self._build_iface_updown(set(irf_p1 + irf_p2), 'up') self.device.stage_config(filename, 'save') if activate: EA = action_element_maker() top = EA.top( EA.IRF( EA.PortConfiguration( EA.Activate() ) ) ) self.device.stage_config(top, 'action') return self.device.staged_to_string()
[docs] def get_config(self): """Get the current configuration of IRF ports on the device. Returns: A dictionary of IRF port bindings. It has the following format:: { <member_id>: { 'irf_p1' : <iface_list>, 'irf_p2' : <iface_list> } } """ irf_ports = {} E = data_element_maker() top = E.top( E.IRF( E.IRFPorts( E.IRFPort( E.Interface() ) ) ) ) nc_get_reply = self.device.get(('subtree', top)) port_elems = findall_in_data('IRFPort', nc_get_reply.data_ele) for port_ele in port_elems: iface_elems = findall_in_data('Interface', port_ele) port_num = find_in_data('Port', port_ele).text member_num = find_in_data('MemberID', port_ele).text if irf_ports.get(member_num) is None: irf_ports[member_num] = {} member_dict = irf_ports[member_num] if len(iface_elems): for iface_ele in iface_elems: iface_name = find_in_data('IfName', iface_ele).text if port_num == '1': if member_dict.get('irf_p1') is None: member_dict['irf_p1'] = [] irf_ports[member_num]['irf_p1'].append(iface_name) elif port_num == '2': if member_dict.get('irf_p2') is None: member_dict['irf_p2'] = [] irf_ports[member_num]['irf_p2'].append(iface_name) return irf_ports
[docs]class IrfMember(object): """This class is used to get and build IRF port configurations on a ``HPCOM7`` device. Args: device (HPCOM7): connected instance of a ``pyhpecw7.comware.HPCOM7`` object. Attributes: device (HPCOM7): connected instance of a ``pyhpecw7.comware.HPCOM7`` object. """ def __init__(self, device): self.device = device def _get_member_config(self, member_id): """Get membership configuration for the specified member ID. Information includes priority, description, and the new member ID. """ irf_members = {} key_map = {'new_member_id': 'NewMemberID', 'descr': 'Description', 'priority': 'Priority'} E = data_element_maker() top = E.top( E.IRF( E.Members( E.Member() ) ) ) nc_get_reply = self.device.get(('subtree', top)) member_eles = findall_in_data('Member', nc_get_reply.data_ele) for member_ele in member_eles: member_num = find_in_data('MemberID', member_ele).text irf_members[member_num] = data_elem_to_dict(member_ele, key_map) return irf_members.get(member_id) def _build_member_config(self, **params): """Build the IRF membership configuration. Configuration parameters include priority, description, and the new member id. Possible parameters: member_id (str) new_member_id (str) priority (str) descr (str) Returns: True is successful. """ member_id = params.get('member_id') descr = params.get('descr') if descr: if not self.device.stage_config( 'irf member {0} description {1}'.format( member_id, descr), 'cli_config'): return False new_member_id = params.get('new_member_id') if new_member_id: if not self.device.stage_config( 'irf member {0} renumber {1}'.format( member_id, new_member_id), 'cli_config'): return False priority = params.get('priority') if priority: if not self.device.stage_config( 'irf member {0} priority {1}'.format( member_id, priority), 'cli_config'): return False return True def _get_domain_config(self): """Return the domain id of switch or IRF stack. Returns: The domain id for the switch or IRF stack. """ key_map = {'domain_id': 'Domain'} E = data_element_maker() top = E.top( E.IRF( E.Configuration() ) ) nc_get_reply = self.device.get(('subtree', top)) reply_data = find_in_data('Configuration', nc_get_reply.data_ele) domain_data = data_elem_to_dict(reply_data, key_map) return domain_data def _get_auto_update_config(self): """Return whether the IRF auto update feature is enabled. Returns: 'enable' or 'disable' """ key_map = {'auto_update': 'AutoUpgrade'} E = data_element_maker() top = E.top( E.IRF( E.Configuration() ) ) nc_get_reply = self.device.get(('subtree', top)) reply_data = find_in_data('Configuration', nc_get_reply.data_ele) au_data = data_elem_to_dict(reply_data, key_map) return au_data def _build_auto_update_domain_config(self, auto_update, domain_id): """Build the auto update config iformation. Args: auto_update (str): 'enable' or 'disable' domain_id (str): The domain id for the switch Returns: The staged config. """ EN = nc_element_maker() EC = config_element_maker() data_eles = [] if auto_update: data_eles.append(EC.AutoUpgrade(auto_update)) if domain_id: data_eles.append(EC.Domain(domain_id)) config = EN.config( EC.top( EC.IRF( EC.Configuration(*data_eles) ) ) ) return self.device.stage_config(config, 'edit_config') def _get_mad_exclude(self): """Get the currently configured mad excluded interfaces Returns: A dictionary:: { 'mad_exclude': <interface list> } """ mad_ex_ifaces = [] raw_rsp = self.device.cli_display( 'display current | inc "mad exclude interface"') lines = raw_rsp.split('\n')[1:-1] for line in lines: mad_ex_ifaces.append(line.split()[-1]) return {'mad_exclude': mad_ex_ifaces} def _build_mad_exclude(self, iface_list): """Build the configuration for adding interfaces to the mad exclude list. """ for iface_name in iface_list: iface = Interface(self.device, iface_name) if not iface.iface_exists: raise InterfaceAbsentError(iface.interface_name) if not self.device.stage_config( 'mad exclude interface {0}'.format( iface.interface_name), 'cli_config'): return False return True
[docs] def get_config(self, member_id): """Return the entire IRF membership configuration for a given member ID. Args: member_id (str): A current IRF member ID for the device. Returns: A dictionary with IRF membership configuration parameters. Including: :auto_update (str): 'enable' or 'disable'. :mad_exclude (list): A list of interfaces to be excluded from MAD mechanisms. :new_member_id (str): The new IRF member ID of the device to applied after reboot. :descr (str): A textual description of the IRF member. :priority (str): The priority of the IRF member. :domain_id (str): The domain id of the member. Raises: IRFMemberDoesntExistError: if the IRF member doesn't exist. """ member_config = self._get_member_config(member_id) if member_config is None: raise IRFMemberDoesntExistError(member_id) au_config = self._get_auto_update_config() madex_config = self._get_mad_exclude() domain_config = self._get_domain_config() member_config.update(au_config) member_config.update(madex_config) member_config.update(domain_config) return member_config
[docs] def build(self, **params): """Build the IRF membership configuration. Args: **params: See Keyword Args. Keyword Args: auto_update (str): OPTIONAL - Enables or disables the auto-upgrade of software after an IRF convergence. Should be 'enable' or 'disable'. mad_exclude (list): OPTIONAL - A list of interfaces to be excluded from MAD mechanisms. member_id (str): REQUIRED - The current IRF member ID of the device. new_member_id (str) REQUIRED - The desired new IRF member ID of the device. domain_id (str) OPTIONAL - The domain id for the IRF member descr (str): OPTIONAL - A textual description of the IRF member. priority (str): OPTIONAL - The desired priority of the IRF member. Returns: True if successful, False otherwise. """ if not self._build_member_config(**params): return False auto_update = params.get('auto_update') domain_id = params.get('domain_id') if auto_update or domain_id: if not self._build_auto_update_domain_config(auto_update, domain_id): return False mad_exclude = params.get('mad_exclude') if mad_exclude: if not self._build_mad_exclude(mad_exclude): return False return True
[docs] def remove_mad_exclude(self, iface_list): """Stage the configuration to remove interfaces from the mad excluded list. """ for iface_name in iface_list: self.device.stage_config( 'undo mad exclude interface {0}'.format( iface_name), 'cli_config')