def delete_port_postcommit(self, mech_context): """Calls cleanup process for C-Fabric. Case1: Baremetal deploy Clear VLAN/LAG for specified physical port. Case2: Otherwise Dissociate MAC address from the portprofile. """ method = 'delete_port_postcommit' port = mech_context.current port_id = port['id'] network_id = port['network_id'] tenant_id = port['tenant_id'] if fj_util.is_baremetal(port): if validate_baremetal_deploy(mech_context): params = self.get_physical_net_params(mech_context) try: self.clear_vlan(params) except Exception: LOG.exception(_LE("Failed to clear vlan%s."), params['vlanid']) raise ml2_exc.MechanismDriverError(method=method) elif not is_supported(mech_context.network): pass else: segments = mech_context.network.network_segments # currently supports only one segment per network segment = segments[0] vfab_id = self._get_vfab_id(segment[driver_api.PHYSICAL_NETWORK]) vlanid = segment[driver_api.SEGMENTATION_ID] interface_mac = port['mac_address'] try: self._driver.dissociate_mac_from_network( self._switch['address'], self._switch['username'], self._switch['password'], vfab_id, vlanid, interface_mac) except Exception: LOG.exception( _LE("Fujitsu Mechanism: failed to dissociate MAC %s") % interface_mac) raise ml2_exc.MechanismDriverError(method=method) LOG.info( _LI("delete port (postcommit): port_id=%(port_id)s " "network_id=%(network_id)s tenant_id=%(tenant_id)s"), {'port_id': port_id, 'network_id': network_id, 'tenant_id': tenant_id})
def _execute(self, cmd): """Execute the command on the switch.""" self._write(cmd + "\n") idx, match, s = self._expect([_PROMPTS_RE]) if idx < 0 or match is None: LOG.error(_LE("Unexpected response from switch: %s"), s) raise ml2_exc.MechanismDriverError(method="_execute") if s.find("<ERROR>") >= 0: LOG.error(_LE("Error is returned from switch: %s"), s) raise ml2_exc.MechanismDriverError(method="_execute") s = _CRLF_RE.sub(r"\n", s) # Remove command and prompt return s[s.find("\n") + 1:s.rfind("\n") + 1]
def _associate_mac_to_port_profile(self, vfab_id, vlanid, mac_address): """Associates a MAC address to a port profile.""" running_config = self.mgr.get_running_config() pprofile = self._create_port_profile( vlanid, mac_address, running_config, commit=False) index, profile_name = _search_vfab_pprofile( vfab_id, mac_address, running_config) if index is None: index = _get_available_vfab_pprofile_index( vfab_id, running_config) if index is None: LOG.error(_LE("No unused vfab pprofile index")) raise ml2_exc.MechanismDriverError( method="_associate_mac_to_port_profile") else: if pprofile == profile_name: return else: LOG.warning( _LW('Override "vfab %(vfab_id)s pprofile %(index)d vsiid ' 'mac %(mac)s %(profile_name)s" to "vsiid mac %(mac)s ' '%(pprofile)s"'), dict(vfab_id=vfab_id, index=index, mac=mac_address, profile_name=profile_name, pprofile=pprofile)) self.mgr.configure( ["vfab {vfab_id} pprofile {index} vsiid mac {mac} " "{pid}".format( vfab_id=vfab_id, index=index, mac=mac_address, pid=pprofile)])
def clear_vlan(self, address, username, password, vfab_id, vlanid, ports, mac): """Clear untagged VLAN. @param self CFABdriver's instance @param address the string of C-Fabric IP address @param username the string of C-Fabric username @param password the string of C-Fabric password @param vfab_id the string of VFAB ID @param vlanid the string of VLAN ID @param ports string of the ports which is separated by ',' @param mac string of the MAC address @return None """ try: self.mgr.connect(address, username, password) config = self.mgr.get_candidate_config() self._dissociate_mac_from_port_profile(vfab_id, vlanid, mac, config=config, do_not_commit=True) self._clear_vlans(vfab_id, ports, config) self._clear_interfaces(ports, commit=True) except (EOFError, EnvironmentError, select.error, ml2_exc.MechanismDriverError): with excutils.save_and_reraise_exception(): LOG.exception(_LE("CLI error"))
def setup_vlan_with_lag(self, address, username, password, vfab_id, vlanid, ports, mac): """Setup untagged VLAN and linkaggregation. @param self CFABdriver's instance @param address the string of C-Fabric IP address @param username the string of C-Fabric username @param password the string of C-Fabric password @param vfab_id the string of VFAB ID @param vlanid the string of VLAN ID @param ports string of the ports which is separated by ',' @param mac string of the MAC address @return None """ try: self.mgr.connect(address, username, password) config = self.mgr.get_candidate_config() modified = self._cleanup_definitions(vfab_id, vlanid, ports, config, mac) self._setup_vlan_with_lag(vfab_id, vlanid, ports, config, ifg=modified, commit=True) except (EOFError, EnvironmentError, select.error, ml2_exc.MechanismDriverError): with excutils.save_and_reraise_exception(): LOG.exception(_LE("CLI error"))
def _reconnect(self): """Re-connect and initialize the CLI session.""" # Close the old connection self._close_session() # Open new TELNET connection try: self._telnet = telnetlib.Telnet( host=self._address, port=TELNET_PORT, timeout=self._timeout) except EnvironmentError: with excutils.save_and_reraise_exception(): LOG.exception(_LE("Connect failed to switch")) try: prompt = "" prompt = self._telnet.read_until(_PROMPT_LOGIN, _TIMEOUT_LOGIN) prompt.index(_PROMPT_LOGIN) self._telnet.write(self._username + "\n") prompt = self._telnet.read_until(_PROMPT_PASS, _TIMEOUT_LOGIN) prompt.index(_PROMPT_PASS) self._telnet.write(self._password + "\n") prompt = self._telnet.read_until(_PROMPT_ADMIN, _TIMEOUT_LOGIN) prompt.index(_PROMPT_ADMIN) except (EOFError, EnvironmentError, ValueError): if _PROMPT_BUSY in prompt: # Wait 3 seconds if self._retry_count < self._max_retry: LOG.warning(_LW("Switch is busy. Wait(%ssec) and retry."), _WAIT_FOR_BUSY) self._retry_count += 1 time.sleep(_WAIT_FOR_BUSY) self._reconnect() return with excutils.save_and_reraise_exception(): self._retry_count = 0 LOG.exception(_LE("Number of retry times has reached.")) else: self._telnet.close() self._telnet = None self._retry_count = 0 with excutils.save_and_reraise_exception(): LOG.exception(_LE("Login failed to switch.(%s)"), prompt) self._retry_count = 0 LOG.debug("Connect success to address %(address)s:%(telnet_port)s", dict(address=self._address, telnet_port=TELNET_PORT))
def _get_mode(self): """Gets the current mode of the switch.""" self._read_eager() self._write("\n") idx, match, s = self._expect([_PROMPTS_RE]) if idx < 0 or match is None: LOG.error(_LE("Unexpected response from switch: %s"), s) raise ml2_exc.MechanismDriverError(method="_get_mode") return _get_mode_from_match(match)
def _get_available_index(target, config): """Gets an available index for specified target resource.""" indices = _INDICES[target] reg = _REG[target] available = indices - set([int(''.join(x)) for x in reg.findall(config)]) if len(available) > 0: return sorted(available)[0] else: LOG.error(_LE("No unused %s index."), target) return None
def _get_vfab_id(self, physical_network): """Get vfab_id corresponding to the physical_network.""" try: vfab_id = self._physical_networks[physical_network] except KeyError: LOG.exception( _LE("Fujitsu Mechanism: network cannot be found in the " "configured physical network")) raise ml2_exc.MechanismDriverError(method="_get_vfab_id") return vfab_id
def clear_vlan(self, params): """Clear VLAN with specified port(s). This method will select driver's method. Case1: param['lag'] is True This method calls 'clear_vlan_with_lag' and clears VLAN and LAG. Case2: param['lag'] is False This method calls 'clear_vlan' and clears only VLAN. @param params A dictionary of the return value for get_physical_net_params @return None """ target = 'clear_vlan_with_lag' call_target = target if params['lag'] else 'clear_vlan' try: clear_method = getattr(self._driver, call_target) except AttributeError: LOG.exception(_LE("Unexpected error happend.")) raise ml2_exc.MechanismDriverError(method="clear_vlan") try: # This plugin supposes 1 C-Fabric(fabric_id) management. # Therefore, not to identify target IP address by using # switch_info(mac_address). LOG.info(_LI("call %(target)s. params: %(params)s"), {'target': call_target, 'params': params}) clear_method( params['address'], params['username'], params['password'], params['vfab_id'], params['vlanid'], params['ports'], params['mac'], ) except Exception: LOG.exception(_LE("Fujitsu Mechanism: " "failed to clear vlan %s"), params['vlanid']) raise ml2_exc.MechanismDriverError(method="clear_vlan")
def _parse_physical_networks(self): """Interpret physical_networks as physical_network:vfab_id entries.""" for entry in cfg.CONF.fujitsu_cfab.physical_networks: try: physical_network, vfab_id = entry.split(':') except ValueError: LOG.exception( _LE("Fujitsu Mechanism: illegal physical_networks entry") ) raise ml2_exc.MechanismDriverError( method="_parse_physical_networks") if not (vfab_id == VFAB_ID_DEFAULT or VFAB_ID_MIN <= int(vfab_id) <= VFAB_ID_MAX): LOG.error( _LE("Fujitsu Mechanism: illegal vfab id in " "physical_networks entry") ) raise ml2_exc.MechanismDriverError( method="_parse_physical_networks") self._physical_networks[physical_network] = vfab_id
def _read_eager(self): """Read readily available data.""" if not self._telnet and self._address: self.connect(self._address, self._username, self._password) try: return self._telnet.read_eager() except (EOFError, EnvironmentError): self._close_session() try: self._reconnect() return self._telnet.read_eager() except (EOFError, EnvironmentError): with excutils.save_and_reraise_exception(): LOG.exception(_LE("Read failed from switch"))
def _write(self, buffer): """Write a string to the switch.""" if not self._telnet and self._address: self.connect(self._address, self._username, self._password) try: self._telnet.write(buffer) except EnvironmentError: self._close_session() try: self._reconnect() self._telnet.write(buffer) except EnvironmentError: with excutils.save_and_reraise_exception(): LOG.exception(_LE("Write failed to switch"))
def _read_until(self, match): """Read until a given string is encountered or until timeout.""" if not self._telnet and self._address: self.connect(self._address, self._username, self._password) try: return self._telnet.read_until(match, self._timeout) except (EOFError, EnvironmentError): self._close_session() try: self._reconnect() return self._telnet.read_until(match, self._timeout) except (EOFError, EnvironmentError): with excutils.save_and_reraise_exception(): LOG.exception(_LE("Read failed from switch"))
def _expect(self, res): """Read until one from a list of a regular expressions matches.""" if not self._telnet and self._address: self.connect(self._address, self._username, self._password) try: return self._telnet.expect(res, timeout=self._timeout) except (EOFError, EnvironmentError, select.error): self._close_session() try: self._reconnect() return self._telnet.expect(res, timeout=self._timeout) except (EOFError, EnvironmentError, select.error): with excutils.save_and_reraise_exception(): LOG.exception(_LE("Read failed from switch"))
def create_port_postcommit(self, mech_context): """Calls setup process for C-Fabric. Case1: Baremetal deploy Setup VLAN for specified physical port. Case2: Otherwise Associate the assigned MAC address to the portprofile. """ if fj_util.is_baremetal(mech_context.current): return if not is_supported(mech_context.network): return method = 'create_port_postcommit' port = mech_context.current port_id = port['id'] network_id = port['network_id'] tenant_id = port['tenant_id'] segments = mech_context.network.network_segments # currently supports only one segment per network segment = segments[0] vfab_id = self._get_vfab_id(segment[driver_api.PHYSICAL_NETWORK]) vlanid = segment[driver_api.SEGMENTATION_ID] interface_mac = port['mac_address'] try: self._driver.associate_mac_to_network(self._switch['address'], self._switch['username'], self._switch['password'], vfab_id, vlanid, interface_mac) except Exception: LOG.exception( _LE("Fujitsu Mechanism: failed to associate mac %s") % interface_mac) raise ml2_exc.MechanismDriverError(method=method) LOG.info( _LI("created port (postcommit): port_id=%(port_id)s " "network_id=%(network_id)s tenant_id=%(tenant_id)s"), {'port_id': port_id, 'network_id': network_id, 'tenant_id': tenant_id})
def _set_mode_config(self): """Sets the configure mode of the switch.""" current = self._get_mode() if current == _MODE_CONFIG: return if current == _MODE_ADMIN: self._write("configure\n") prompt = self._read_until(_PROMPT_CONFIG) elif current == _MODE_CONFIG_IF: self._write("exit\n") prompt = self._read_until(_PROMPT_CONFIG) else: self._reconnect() self._write("configure\n") prompt = self._read_until(_PROMPT_CONFIG) if prompt.find(_PROMPT_CONFIG) < 0: LOG.error(_LE("Failed to set configure mode.")) raise ml2_exc.MechanismDriverError(method="_set_mode_config")
def dissociate_mac_from_network(self, address, username, password, vfab_id, net_id, mac): """Dissociates a MAC address from virtual network. @param self CFABdriver's instance @param address the string of C-Fabric IP address @param username the string of C-Fabric username @param password the string of C-Fabric password @param vfab_id the string of VFAB ID @param net_id the string of VLAN ID(segmentation_id for network) @param mac the string of MAC address @return None """ try: self.mgr.connect(address, username, password) self._dissociate_mac_from_port_profile(vfab_id, net_id, mac) except (EOFError, EnvironmentError, select.error, ml2_exc.MechanismDriverError): with excutils.save_and_reraise_exception(): LOG.exception(_LE("CLI error"))