def raise_mechanism_exc(*args, **kwargs): raise ml2_exc.MechanismDriverError( method='create_network_postcommit')
def mock_update_network_postcommit(self, context): raise ml2_exc.MechanismDriverError( method='update_network_postcommit')
def create_network(self, vlan_id, ports): if self.error: raise ml2_exc.MechanismDriverError(method='create_network') vlan_map = {} vlan_map.update({vlan_id: ports}) config_map.update({self.address: vlan_map})
def delete_network(self, vlan_id): vlan_map = config_map.pop(self.address, None) if vlan_map is None: raise ml2_exc.MechanismDriverError(method='delete_network') else: vlan_map.pop(vlan_id, None)
def update_port_postcommit(self, context): """Update the name of a given port in EOS. At the moment we only support port name change Any other change to port is not supported at this time. """ port = context.current orig_port = context.original device_id = port['device_id'] device_owner = port['device_owner'] host = context.host is_vm_boot = device_id and device_owner vnic_type = port['binding:vnic_type'] binding_profile = port['binding:profile'] bindings = [] if binding_profile: bindings = binding_profile['local_link_information'] port_id = port['id'] port_name = port['name'] network_id = port['network_id'] tenant_id = port['tenant_id'] or INTERNAL_TENANT_ID # Ensure that we use tenant Id for the network owner tenant_id = self._network_owner_tenant(context, network_id, tenant_id) sg = port['security_groups'] orig_sg = orig_port['security_groups'] pretty_log("update_port_postcommit: new", port) pretty_log("update_port_postcommit: orig", orig_port) # Check if it is port migration case if self._handle_port_migration_postcommit(context): # Return from here as port migration is already handled. return seg_info = self._bound_segments(context) if not seg_info: LOG.debug("Ignoring the update as the port is not managed by " "Arista switches.") return with self.eos_sync_lock: hostname = self._host_name(host) segmentation_id = seg_info[driver_api.SEGMENTATION_ID] port_host_filter = None if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE): # <port, host> uniquely identifies a DVR port. Other # ports are identified by just the port id port_host_filter = host port_provisioned = db_lib.is_port_provisioned( port_id, port_host_filter) # If network does not exist under this tenant, # it may be a shared network. Get shared network owner Id net_provisioned = self._network_provisioned( tenant_id, network_id, segmentation_id=segmentation_id) segments = [] if net_provisioned: if self.rpc.hpb_supported(): for binding_level in context.binding_levels: bound_segment = binding_level.get( driver_api.BOUND_SEGMENT) if bound_segment: segments.append(bound_segment) all_segments = self.ndb.get_all_network_segments( network_id, context=context._plugin_context) try: self.rpc.create_network_segments( tenant_id, network_id, context.network.current['name'], all_segments) except arista_exc.AristaRpcError: LOG.error(_LE("Failed to create network segments")) raise ml2_exc.MechanismDriverError() else: # For non HPB cases, the port is bound to the static # segment segments = self.ndb.get_network_segments(network_id) try: orig_host = context.original_host port_down = False if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE ): # We care about port status only for DVR ports port_down = context.status == n_const.PORT_STATUS_DOWN if orig_host and (port_down or host != orig_host): try: LOG.info("Deleting the port %s" % str(orig_port)) # The port moved to a different host or the VM # connected to the port was deleted or its in DOWN # state. So delete the old port on the old host. self._delete_port(orig_port, orig_host, tenant_id) except ml2_exc.MechanismDriverError: # If deleting a port fails, then not much can be done # about it. Log a warning and move on. LOG.warning(UNABLE_TO_DELETE_PORT_MSG) if (port_provisioned and net_provisioned and hostname and is_vm_boot and not port_down): LOG.info(_LI("Port plugged into network")) # Plug port into the network only if it exists in the db # and is bound to a host and the port is up. self.rpc.plug_port_into_network(device_id, hostname, port_id, network_id, tenant_id, port_name, device_owner, sg, orig_sg, vnic_type, segments=segments, switch_bindings=bindings) else: LOG.info(_LI("Port not plugged into network")) except arista_exc.AristaRpcError as err: LOG.error( _LE('update_port_postcommit: Did not update ' 'port %(port_id)s. Reason: %(err)s'), { 'port_id': port_id, 'err': err })
def _raise_ml2_error(self, err_type, method_name): base.FAULT_MAP.update({ml2_exc.MechanismDriverError: err_type}) raise ml2_exc.MechanismDriverError(method=method_name)
def create_network_postcommit(self, mech_context): """Create VLAN on the switch. :param:mech_context: Details about the network to be created :raise: Exception """ LOG.debug("create_network_postcommit: called") network = mech_context.current network_id = network['id'] tenant_id = network['tenant_id'] segments = mech_context.network_segments network_type = segments[0]['network_type'] vlan_id = segments[0]['segmentation_id'] physical_network = segments[0]['physical_network'] if physical_network not in self._physical_networks: LOG.exception(_LE("BrocadeFiNiMechanism: Failed to create network." " Network cannot be created in the configured " "physical network %(physnet)s"), {'physnet': physical_network}) raise ml2_exc.MechanismDriverError(method='create_network_postcomm' 'it') if network_type != 'vlan': LOG.exception(_LE("BrocadeFiNiMechanism: Failed to create network " "for network type %(nw_type)s. Only network type" " vlan is supported"), {'nw_type': network_type}) raise ml2_exc.MechanismDriverError(method='create_network_postcomm' 'it') try: devices = self._physical_networks.get(physical_network) for device in devices: device_info = self._devices.get(device) address = device_info.get('address') driver = None try: driver = self._get_driver(device) except Exception as e: LOG.exception(_LE("BrocadeFiNiMechanism: create_network" "_postcommit failed while configuring " "device %(host)s exception=%(error)s"), {'host': address, 'error': e.args}) raise ml2_exc.MechanismDriverError(method='create_network_' 'postcommit') # Proceed only if the driver is not None if driver is not None: driver.create_network( vlan_id, device_info.get("ports").split(",")) except Exception as e: LOG.exception( _LE("Brocade FI/NI driver: create_network_postcommit failed" "Error = %(error)s"), {'error': e.args}) raise ml2_exc.MechanismDriverError(method='create_network_postcomm' 'it') LOG.info(_LI("BrocadeFiNiMechanism:created_network_postcommit: " "%(network_id)s of network type = %(network_type)s with " "vlan = %(vlan_id)s for tenant %(tenant_id)s"), {'network_id': network_id, 'network_type': network_type, 'vlan_id': vlan_id, 'tenant_id': tenant_id})
def __restRequestError__(self, errorCode, reason): LOG.error("----------restRequest error") LOG.debug(("----------the reason is: %s"), reason) LOG.debug(("----------the errorCode is: %s"), errorCode) raise ml2_exc.MechanismDriverError()
def create_subnet_postcommit(self, mech_context, update=False): if not update: # log the context for debugging LOG.debug("create_subnetwork_postcommit: called, context %(ctx)s", {'ctx': mech_context.current}) gateway = mech_context.current['gateway_ip'] network_id = mech_context.current['network_id'] subnet_id = mech_context.current['id'] tenant_id = mech_context.current['tenant_id'] context = mech_context._plugin_context dns_nameservers = mech_context.current.setdefault( 'dns_nameservers', []) if update: router_func = utils.set_routerstatic dhcp_func = utils.set_dhcpserver else: router_func = utils.add_routerstatic dhcp_func = utils.add_dhcpserver try: if fortinet_db.query_record(context, ext_db.ExternalNetwork, network_id=network_id): router_func(self, context, subnet_id=subnet_id, vdom=const.EXT_VDOM, dst=const.EXT_DEF_DST, device=self._fortigate['ext_interface'], gateway=gateway) else: namespace = fortinet_db.query_record( context, fortinet_db.Fortinet_ML2_Namespace, tenant_id=tenant_id) interface = utils.get_intf(context, mech_context.current['network_id']) netmask = str( netaddr.IPNetwork(mech_context.current['cidr']).netmask) start_ip = mech_context.current['allocation_pools'][0]['start'] end_ip = mech_context.current['allocation_pools'][0]['end'] dhcp_func(self, context, subnet_id=subnet_id, vdom=namespace.vdom, interface=interface, dns_nameservers=dns_nameservers, gateway=gateway, netmask=netmask, start_ip=start_ip, end_ip=end_ip) # TODO(samsu): need to add rollback for the update and set cls = fortinet_db.Fortinet_Interface record = fortinet_db.query_record(context, cls, name=interface, vdom=namespace.vdom) if gateway: cls.update_record(context, record, ip="%s %s" % (gateway, netmask)) utils.op(self, context, resources.VlanInterface.set, name=interface, vdom=namespace.vdom, ip="%s %s" % (gateway, netmask)) except Exception as e: utils._rollback_on_err(self, context, e) raise ml2_exc.MechanismDriverError( method=sys._getframe().f_code.co_name) if not update: utils.update_status(self, context, t_consts.TaskStatus.COMPLETED)
def create_subnet_postcommit(self, mech_context): """Noop now, it is left here for future.""" #LOG.debug(_("create_subnetwork_postcommit: called")) gateway = mech_context.current['gateway_ip'] network_id = mech_context.current['network_id'] subnet_id = mech_context.current['id'] tenant_id = mech_context.current['tenant_id'] context = mech_context._plugin_context try: if fortinet_db.query_record(context, ExternalNetwork, network_id=network_id): utils.add_routerstatic(self, context, subnet_id=subnet_id, vdom=const.EXT_VDOM, dst=const.EXT_DEF_DST, device=self._fortigate['ext_interface'], gateway=gateway) else: namespace = fortinet_db.query_record( context, fortinet_db.Fortinet_ML2_Namespace, tenant_id=tenant_id) interface = utils.get_intf(context, mech_context.current['network_id']) netmask = str(netaddr.\ IPNetwork(mech_context.current['cidr']).netmask) start_ip = mech_context.current['allocation_pools'][0]['start'] end_ip = mech_context.current['allocation_pools'][0]['end'] utils.add_dhcpserver(self, context, subnet_id=subnet_id, vdom=namespace.vdom, interface=interface, gateway=gateway, netmask=netmask, start_ip=start_ip, end_ip=end_ip) # TODO: need to add rollback for the update and set cls = fortinet_db.Fortinet_Interface record = fortinet_db.query_record(context, cls, name=interface, vdom=namespace.vdom) if gateway: cls.update_record(context, record, ip="%s %s" % (gateway, netmask)) utils.op(self, context, resources.VlanInterface.set, name=interface, vdom=namespace.vdom, ip="%s %s" % (gateway, netmask)) except Exception as e: utils._rollback_on_err(self, context, e) raise ml2_exc.MechanismDriverError( method=sys._getframe().f_code.co_name) utils.update_status(self, context, t_consts.TaskStatus.COMPLETED)
def bind_port(self, context): """Attempt to bind a port. :param context: PortContext instance describing the port This method is called outside any transaction to attempt to establish a port binding using this mechanism driver. Bindings may be created at each of multiple levels of a hierarchical network, and are established from the top level downward. At each level, the mechanism driver determines whether it can bind to any of the network segments in the context.segments_to_bind property, based on the value of the context.host property, any relevant port or network attributes, and its own knowledge of the network topology. At the top level, context.segments_to_bind contains the static segments of the port's network. At each lower level of binding, it contains static or dynamic segments supplied by the driver that bound at the level above. If the driver is able to complete the binding of the port to any segment in context.segments_to_bind, it must call context.set_binding with the binding details. If it can partially bind the port, it must call context.continue_binding with the network segments to be used to bind at the next lower level. If the binding results are committed after bind_port returns, they will be seen by all mechanism drivers as update_port_precommit and update_port_postcommit calls. But if some other thread or process concurrently binds or updates the port, these binding results will not be committed, and update_port_precommit and update_port_postcommit will not be called on the mechanism drivers with these results. Because binding results can be discarded rather than committed, drivers should avoid making persistent state changes in bind_port, or else must ensure that such state changes are eventually cleaned up. Implementing this method explicitly declares the mechanism driver as having the intention to bind ports. This is inspected by the QoS service to identify the available QoS rules you can use with ports. """ port = context.current network = context.network.current switch_name, switch_port, segmentation_id = \ self._link_info_from_port(port, network) if not self._is_port_supported(port): LOG.debug('Port {} has vnic_type set to %s which is not correct ' 'to work with networking-ansible driver.'.format( port['id'], port[portbindings.VNIC_TYPE])) return segments = context.segments_to_bind LOG.debug('Plugging in port {switch_port} on ' '{switch_name} to vlan: {segmentation_id}'.format( switch_port=switch_port, switch_name=switch_name, segmentation_id=segmentation_id)) provisioning_blocks.add_provisioning_component( context._plugin_context, port['id'], resources.PORT, ANSIBLE_NETWORKING_ENTITY) # Assign port to network try: self.ansnet.update_access_port(switch_name, switch_port, segmentation_id) context.set_binding(segments[0][ml2api.ID], portbindings.VIF_TYPE_OTHER, {}) LOG.info('Port {neutron_port} has been plugged into ' 'network {net_id} on device {switch_name}'.format( neutron_port=port['id'], net_id=network['id'], switch_name=switch_name)) except Exception as e: LOG.error('Failed to plug in port {neutron_port} on ' 'device: {switch_name} from network {net_id} ' 'reason: {exc}'.format(neutron_port=port['id'], net_id=network['id'], switch_name=switch_name, exc=e)) raise ml2_exc.MechanismDriverError(e)
def create_network_postcommit(self, context): """Create a network. :param context: NetworkContext instance describing the new network. Called after the transaction commits. Call can block, though will block the entire process so care should be taken to not drastically affect performance. Raising an exception will cause the deletion of the resource. """ # assuming all hosts # TODO(radez): can we filter by physnets? # TODO(michchap): we should be able to do each switch in parallel # if it becomes a performance issue. switch topology might also # open up options for filtering. for host_name in self.ml2config.inventory: host = self.ml2config.inventory[host_name] if host.get('manage_vlans', True): network = context.current network_id = network['id'] provider_type = network['provider:network_type'] segmentation_id = network['provider:segmentation_id'] lock = self.coordinator.get_lock(host_name) with lock: if provider_type == 'vlan' and segmentation_id: # re-request network info in case it's stale net = Network.get_object(context._plugin_context, id=network_id) LOG.debug('network create object: {}'.format(net)) # network was since deleted by user and we can discard # this request if not net: return # check the vlan for this request is still associated # with this network. We don't currently allow updating # the segment on a network - it's disallowed at the # neutron level for provider networks - but that could # change in the future s_ids = [s.segmentation_id for s in net.segments] if segmentation_id not in s_ids: return # Create VLAN on the switch try: self.net_runr.create_vlan( host_name, segmentation_id, **self.extra_params[host_name]) LOG.info('Network {net_id}, segmentation ' '{seg} has been added on ' 'ansible host {host}'.format( net_id=network['id'], seg=segmentation_id, host=host_name)) except Exception as e: # TODO(radez) I don't think there is a message # returned from ansible runner's # exceptions LOG.error('Failed to create network {net_id} ' 'on ansible host: {host}, ' 'reason: {err}'.format(net_id=network_id, host=host_name, err=e)) raise ml2_exc.MechanismDriverError(e)
def delete_network_postcommit(self, context): """Delete a network. :param context: NetworkContext instance describing the current state of the network, prior to the call to delete it. Called after the transaction commits. Call can block, though will block the entire process so care should be taken to not drastically affect performance. Runtime errors are not expected, and will not prevent the resource from being deleted. """ # assuming all hosts # TODO(radez): can we filter by physnets? LOG.debug('ansnet:network delete') for host_name in self.ml2config.inventory: host = self.ml2config.inventory[host_name] network = context.current provider_type = network['provider:network_type'] segmentation_id = network['provider:segmentation_id'] physnet = network['provider:physical_network'] if provider_type == 'vlan' and segmentation_id: if host.get('manage_vlans', True): lock = self.coordinator.get_lock(host_name) with lock: # Find out if this segment is active. # We need to find out if this segment is being used # by another network before deleting it from the switch # since reordering could mean that a vlan is recycled # by the time this request is satisfied. Getting # the current network is not enough db = context._plugin_context segments = NetworkSegment.get_objects( db, segmentation_id=segmentation_id) for segment in segments: if (segment.segmentation_id == segmentation_id and segment.physical_network == physnet and segment.network_type == 'vlan'): LOG.debug('Not deleting segment {} from {}' 'because it was recreated'.format( segmentation_id, physnet)) return # Delete VLAN on the switch try: self.net_runr.delete_vlan( host_name, segmentation_id, **self.extra_params[host_name]) LOG.info('Network {net_id} has been deleted on ' 'ansible host {host}'.format( net_id=network['id'], host=host_name)) except Exception as e: LOG.error('Failed to delete network {net} ' 'on ansible host: {host}, ' 'reason: {err}'.format(net=network['id'], host=host_name, err=e)) raise ml2_exc.MechanismDriverError(e)