def set_switchport_mode(self, port, mode, vlan=None): port = str(port) cmd = self.IFC_ETH_CFG.format(port) + self.SEP cmd += self.SWITCHPORT_MODE.format(mode.value) if vlan: if mode.value == 'trunk': cmd += self.SEP + self.SWITCHPORT_TRUNK_NATIVE_VLAN.format( vlan) if mode.value == 'access': cmd += self.SEP + self.SWITCHPORT_ACCESS_VLAN.format(vlan) self.send_cmd(cmd) ports = self.show_ports(format='std') if port not in ports: msg = 'Unable to verify setting of switchport mode' msg += 'for port {}. May already be in a channel group.' msg.format(port) self.log.debug(msg) return if self.mode == 'passive' or ports[port]['mode'] == mode.value: self.log.debug('Port {} is in {} mode'.format(port, mode.value)) else: raise SwitchException('Failed setting port {} to {} mode'.format( port, mode.value)) if vlan: if self.mode == 'passive' or str(vlan) == ports[port]['nvlan']: msg = 'PVID/Native vlan {} set on port {}'.format(vlan, port) self.log.debug(msg) else: msg = 'Failed setting PVID/Native vlan {} on port {}'.format( vlan, port) self.log.error(msg) raise SwitchException(msg)
def remove_interface(self, vlan, host, netmask): """Removes an in-band management interface. Args: host (string): hostname or ipv4 address in dot decimal notation netmask (string): netmask in dot decimal notation vlan (int or string): value between 1 and 4094. raises: SwitchException if unable to remove interface """ vlan = str(vlan) interfaces = self.show_interfaces(vlan, host, netmask, format='std') if interfaces[-1][0]['configured']: self.send_cmd('interface vlan {} ;no ip address {} {}'.format( vlan, host, netmask)) self.send_cmd('no interface vlan {}'.format(vlan)) interfaces = self.show_interfaces(vlan, host, netmask, format='std') if interfaces[-1][0]['configured']: self.log.debug( 'Failed to remove interface Vlan {}.'.format(vlan)) raise SwitchException( 'Failed to remove interface Vlan {}.'.format(vlan)) else: if interfaces[-1][0]['found vlan']: self.log.debug( 'Specified interface on vlan {} does not exist.'.format( vlan)) raise SwitchException( 'Failed to remove interface Vlan {}.'.format(vlan))
def delete_vlan(self, vlan): self.send_cmd(self.DELETE_VLAN.format(vlan)) if self.mode == 'active' and self.is_vlan_created(vlan): self.log.warning('Failed deleting VLAN {}'.format(vlan)) raise SwitchException('Failed deleting VLAN {}'.format(vlan)) self.log.info('vlan {} deleted.'.format(vlan)) return
def bind_ports_to_mlag_interface(self, ports, mlag_ifc=None): """ Bind ports to an MLAG interface and enable it. If no mlag interface is specified, the port is bound to the mlag interface number matching the first port number. Args: port: (int or string) Physical port to add to the MLAG port channel mlag_ifc: (int or string) MLAG interface (MLAG port channel) This port channel must already exist. (create_mlag_interface(self, mlag_ifc)) """ if mlag_ifc is None: mlag_ifc = min(ports) for port in ports: self.send_cmd( self.IFC_ETH_CFG.format(port) + self.SEP + self.MLAG_ACTIVE.format(mlag_ifc)) self.send_cmd( self.MLAG_PORT_CHANNEL.format(mlag_ifc) + self.SEP + self.NO_SHUTDOWN) mlag_port_chan_summ = self.send_cmd(self.SHOW_IFC_MLAG_PORT_CHANNEL) for port in ports: if 'Eth1/' + str(port) not in mlag_port_chan_summ: self.log.error( 'Port {} not added to mlag port channel {}'.format( port, mlag_ifc)) raise SwitchException( 'Port {} not added to mlag port channel {}'.format( port, mlag_ifc))
def configure_interface(self, host, netmask, vlan=1, intf=None): """Configures a management interface. This implementation checks if the host ip is already in use. If it is, a check is made to see if it is configured as specified. If not, an exception is raised. Lenovo numbers interfaces. The specified vlan will be created if it does not already exist. When implementing this method for a new switch, minimally this method should configure (overwrite if necessary) the specified interface. Args: host (string): hostname or ipv4 address in dot decimal notation netmask (string): netmask in dot decimal notation vlan (string): String representation of integer between 1 and 4094. The management interface is created on the specified vlan intf (string): optional. String representation of integer between 1 and 128. raises: SwitchException if unable to program interface """ vlan = str(vlan) interfaces = self.show_interfaces(vlan, host, netmask, format='std') if interfaces[-1][0]['configured']: self.log.debug( 'Switch interface vlan {} already configured'.format(vlan)) return if interfaces[-1][0]['found vlan']: self.log.debug( 'Conflicting address. Interface vlan {} already configured'. format(vlan)) raise SwitchException( 'Conflicting address exists on interface vlan {}'.format(vlan)) return # create vlan if it does not already exist self.create_vlan(vlan) # create the interface self.send_cmd(self.SET_INTERFACE.format(vlan, host, netmask)) interfaces = self.show_interfaces(vlan, host, netmask, format='std') if not interfaces[-1][0]['configured']: raise SwitchException( 'Failed configuring management interface vlan {}'.format(vlan))
def configure_interface(self, host, netmask, vlan): """Configures a management interface. Minimally, this method will configure (overwrite if necessary) the specified interface. A better behaved implementation will check if host ip is already in use. If it is, it checks to see if it is configured as specified. If not, an exception is raised. If no interface number is specified, it will use the next available unconfigured interface. The specified vlan will be created if it does not already exist. Args: host (string): hostname or ipv4 address in dot decimal notation netmask (string): netmask in dot decimal notation vlan (int or string): Integer between 1 and 4094. If none specified, usually the default vlan is used. raises: SwitchException if unable to program interface """ vlan = str(vlan) interfaces = self.show_interfaces(vlan, host, netmask, format='std') if interfaces[-1][0]['configured']: self.log.debug( 'Switch interface vlan {} already configured'.format(vlan)) return if interfaces[-1][0]['found vlan']: self.log.debug( 'Conflicting address. Interface vlan {} already configured'. format(vlan)) raise SwitchException( 'Conflicting address exists on interface vlan {}'.format(vlan)) return # create vlan if it does not already exist self.create_vlan(vlan) # create the interface self.send_cmd(self.SET_INTERFACE.format(vlan, host, netmask)) interfaces = self.show_interfaces(vlan, host, netmask, format='std') if not interfaces[-1][0]['configured']: raise SwitchException( 'Failed configuring management interface vlan {}'.format(vlan))
def add_ports_to_port_channel_ifc(self, ports, lag_ifc, mode='active'): # Map a physical port to the LAG in specified mode (active for LACP) for port in ports: cmd = self.IFC_ETH_CFG.format(port) + self.SEP + \ self.CHANNEL_GROUP_MODE.format(lag_ifc, mode) self.send_cmd(cmd) port_chan_summ = self.show_port_channel_interfaces() for port in ports: if not re.findall(self.PORT_PREFIX + str(port) + r'[\s+|\(]', port_chan_summ): self.log.error('Port {} not added to port channel {}'.format( port, lag_ifc)) raise SwitchException('Port {} not added to port channel {}'. format(port, lag_ifc))
def add_vlans_to_port_channel(self, port, vlans): """ DEPRECATED """ ports = self.show_ports('std') port = str(port) if port not in ports: raise SwitchException( 'Port inaccessible (may already be in port channel).' '\nFailed adding vlans {} to port {}'.format(vlans, port)) # Enable trunk mode for port self.send_cmd(self.SET_LAG_PORT_CHANNEL_MODE_TRUNK.format(port)) # Add VLANs to port for vlan in vlans: self.send_cmd( self.LAG_PORT_CHANNEL.format(port) + 'switchport trunk allowed vlan add {}'.format(vlan))
def send_cmd(self, cmd): if self.mode == 'passive': f = open(self.outfile, 'a+') f.write(cmd + '\n') f.close() return host_ip = gethostbyname(self.host) lockfile = os.path.join(SWITCH_LOCK_PATH, host_ip + '.lock') if not os.path.isfile(lockfile): os.mknod(lockfile) os.chmod(lockfile, stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU) lock = FileLock(lockfile) cnt = 0 while cnt < 5 and not lock.is_locked: if cnt > 0: self.log.info('Waiting to acquire lock for switch {}'. format(self.host)) cnt += 1 try: lock.acquire(timeout=5, poll_intervall=0.05) # 5 sec, 50 ms sleep(0.01) # give switch a chance to close out comms except Timeout: pass if lock.is_locked: if self.ENABLE_REMOTE_CONFIG: cmd = self.ENABLE_REMOTE_CONFIG.format(cmd) self.log.debug(cmd) ssh = SSH() __, data, _ = ssh.exec_cmd( self.host, self.userid, self.password, cmd, ssh_log=True, look_for_keys=False) lock.release() # sleep 60 ms to give other processes a chance. sleep(0.06 + random() / 100) # lock acquire polls at 50 ms if lock.is_locked: self.log.error('Lock is locked. Should be unlocked') return data.decode("utf-8") else: self.log.error('Unable to acquire lock for switch {}'.format(self.host)) raise SwitchException('Unable to acquire lock for switch {}'. format(self.host))
def send_cmd(self, cmd): if self.mode == 'passive': f = open(self.outfile, 'a+') f.write(cmd + '\n') f.close() return host_ip = gethostbyname(self.host) lockfile = os.path.join('/var/lock', host_ip + '.lock') if not os.path.isfile(lockfile): os.mknod(lockfile) os.chmod(lockfile, stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU) lock = FileLock(lockfile) cnt = 0 while cnt < 5 and not lock.is_locked: if cnt > 0: self.log.info('Waiting to acquire lock for switch {}'.format( self.host)) cnt += 1 try: lock.acquire(timeout=5) # 5 sec except Timeout: pass if lock.is_locked: if self.ENABLE_REMOTE_CONFIG: cmd = self.ENABLE_REMOTE_CONFIG.format(cmd) self.log.debug(cmd) ssh = SSH() __, data, _ = ssh.exec_cmd(self.host, self.userid, self.password, cmd, ssh_log=True, look_for_keys=False) lock.release() return data else: self.log.error('Unable to acquire lock for switch {}'.format( self.host)) raise SwitchException( 'Unable to acquire lock for switch {}'.format(self.host))
def configure_interface(self, host, netmask, vlan=1, intf=None): """Configures a management interface. This implementation checks if the host ip is already in use. If it is, a check is made to see if it is configured as specified. If not, an exception is raised. Lenovo numbers interfaces. If no interface number is specified, the next available unconfigured interface is used. The specified vlan will be created if it does not already exist. When implementing this method for a new switch, minimally this method should configure (overwrite if necessary) the specified interface. Args: host (string): hostname or ipv4 address in dot decimal notation netmask (string): netmask in dot decimal notation vlan (string): Optional. string representation of integer between 1 and 4094. If none specified, usually the default vlan is used. intf (string): optional. String representation of integer between 1 and 128. raises: SwitchException if unable to program interface """ interfaces = self.show_interfaces(vlan, host, netmask, format='std') if self.mode == 'active' and interfaces[-1][0]['configured']: self.log.debug( 'Switch interface {} already configured'.format( interfaces[-1][0]['found ifc'])) return if vlan is not None: self.create_vlan(vlan) if self.mode == 'active' and intf is None: intf = interfaces[-1][0]['avail ifc'] self.send_cmd(self.CREATE_INTERFACE.format(intf, host, netmask, vlan)) interfaces = self.show_interfaces(vlan, host, netmask, format='std') if self.mode == 'active' and not interfaces[-1][0]['configured']: self.log.error( 'Failed configuring management interface ip {}'.format(intf)) raise SwitchException( 'Failed configuring management interface ip {}'.format(intf)) return
def create_vlan(self, vlan): self.send_cmd(self.CREATE_VLAN.format(vlan)) if self.mode == 'passive' or self.is_vlan_created(vlan): self.log.debug('Created VLAN {}'.format(vlan)) else: raise SwitchException('Failed creating VLAN {}'.format(vlan))
def deconfigure_mlag(self): if not self.is_mlag_configured(): self.log.debug('MLAG is not configured on switch {}'.format( self.host)) return # Get MLAG info. Note that Mellanox supports only 1 IPL port channel mlag_info = self.send_cmd(self.SHOW_MLAG) match = re.search(r'\d+\s+Po(\d+)\s+(\d+)', mlag_info) if match: port_channel = match.group(1) vlan = match.group(2) self.log.debug( 'Found IPL port channel {} on vlan {}. Removing.'.format( port_channel, vlan)) else: raise SwitchException('MLAG port channel information not found') port_channel_info = self.send_cmd(self.SHOW_PORT_CHANNEL) match = re.search( r'\d+\s+Po' + port_channel + '\S+\s+\w+\s+Eth1/(\d+)\S+\s+Eth1/(\d+)', port_channel_info) if match: port1 = match.group(1) port2 = match.group(2) self.log.debug('Found IPL ports {} {}'.format(port1, port2)) else: raise SwitchException( 'MLAG IPL port channel information not found') self.disable_mlag() self.send_cmd(self.NO_MLAG_VIP) # Remove IPL peer address self.send_cmd( self.INTERFACE_VLAN.format(vlan) + self.SEP + self.NO_IPL_PEER_ADDRESS) # Remove IPL address self.send_cmd( self.INTERFACE_VLAN.format(vlan) + self.SEP + self.NO_IP_CIDR) # Remove the interface on vlan self.send_cmd(self.NO_INTERFACE_VLAN.format(vlan)) # Turn off QOS dcb priority flow control on port channel self.send_cmd( self.IFC_PORT_CH_CFG.format(port_channel) + self.SEP + self.QOS_OFF) # Unbind IPL 1 from port channel self.send_cmd( self.IFC_PORT_CH_CFG.format(port_channel) + self.SEP + self.NO_IPL) # Remove physical ports from channel group self.send_cmd( self.IFC_ETH_CFG.format(port1) + self.SEP + '"no channel-group"') self.send_cmd( self.IFC_ETH_CFG.format(port2) + self.SEP + '"no channel-group"') # Remove the port channel self.send_cmd(self.NO_IFC_PORT_CH_CFG.format(port_channel)) # Remove the vlan self.send_cmd(self.DELETE_VLAN.format(vlan)) # Disable mlag protocol self.send_cmd(self.NO_MLAG) # Disable QOS self.send_cmd(self.NO_QOS_ENABLE)