def delete_circuit(self, circuit_id): """Remove a circuit. First, the flows are removed from the switches, and then the EVC is disabled. """ log.debug("delete_circuit /v2/evc/%s", circuit_id) try: evc = self.circuits[circuit_id] except KeyError: result = f"circuit_id {circuit_id} not found" log.debug("delete_circuit result %s %s", result, 404) raise NotFound(result) from NotFound if evc.archived: result = f"Circuit {circuit_id} already removed" log.debug("delete_circuit result %s %s", result, 404) raise NotFound(result) from NotFound log.info("Removing %s", evc) with evc.lock: evc.remove_current_flows() evc.deactivate() evc.disable() self.sched.remove(evc) evc.archive() evc.sync() log.info("EVC removed. %s", evc) result = {"response": f"Circuit {circuit_id} removed"} status = 200 log.debug("delete_circuit result %s %s", result, status) emit_event(self.controller, "deleted", evc_id=evc.id) return jsonify(result), status
def update(self, circuit_id): """Update a circuit based on payload. The EVC required attributes (name, uni_a, uni_z) can't be updated. """ log.debug("update /v2/evc/%s", circuit_id) try: evc = self.circuits[circuit_id] except KeyError: result = f"circuit_id {circuit_id} not found" log.debug("update result %s %s", result, 404) raise NotFound(result) from NotFound if evc.archived: result = "Can't update archived EVC" log.debug("update result %s %s", result, 405) raise MethodNotAllowed(["GET"], result) try: data = request.get_json() except BadRequest: result = "The request body is not a well-formed JSON." log.debug("update result %s %s", result, 400) raise BadRequest(result) from BadRequest if data is None: result = "The request body mimetype is not application/json." log.debug("update result %s %s", result, 415) raise UnsupportedMediaType(result) from UnsupportedMediaType try: enable, redeploy = evc.update( **self._evc_dict_with_instances(data) ) except ValueError as exception: log.error(exception) log.debug("update result %s %s", exception, 400) raise BadRequest(str(exception)) from BadRequest if evc.is_active(): if enable is False: # disable if active with evc.lock: evc.remove() elif redeploy is not None: # redeploy if active with evc.lock: evc.remove() evc.deploy() else: if enable is True: # enable if inactive with evc.lock: evc.deploy() result = {evc.id: evc.as_dict()} status = 200 log.debug("update result %s %s", result, status) emit_event(self.controller, "updated", evc_id=evc.id, data=data) return jsonify(result), status
def deploy(self): """Deploy EVC to best path. Best path can be the primary path, if available. If not, the backup path, and, if it is also not available, a dynamic path. """ if self.archived: return False self.enable() success = self.deploy_to_primary_path() if not success: success = self.deploy_to_backup_path() if success: emit_event(self._controller, "deployed", evc_id=self.id) return success
def handle_link_down(self, event): """Change circuit when link is down or under_mantenance.""" log.debug("Event handle_link_down %s", event) for evc in self.circuits.values(): with evc.lock: if evc.is_affected_by_link(event.content["link"]): log.debug(f"Handling evc {evc.id} on link down") if evc.handle_link_down(): emit_event( self.controller, "redeployed_link_down", evc_id=evc.id, ) else: emit_event( self.controller, "error_redeploy_link_down", evc_id=evc.id, )
def create_circuit(self, data): """Try to create a new circuit. Firstly, for EVPL: E-Line NApp verifies if UNI_A's requested C-VID and UNI_Z's requested C-VID are available from the interfaces' pools. This is checked when creating the UNI object. Then, E-Line NApp requests a primary and a backup path to the Pathfinder NApp using the attributes primary_links and backup_links submitted via REST # For each link composing paths in #3: # - E-Line NApp requests a S-VID available from the link VLAN pool. # - Using the S-VID obtained, generate abstract flow entries to be # sent to FlowManager Push abstract flow entries to FlowManager and FlowManager pushes OpenFlow entries to datapaths E-Line NApp generates an event to notify all Kytos NApps of a new EVC creation Finnaly, notify user of the status of its request. """ # Try to create the circuit object log.debug("create_circuit /v2/evc/") try: evc = self._evc_from_dict(data) except ValueError as exception: log.debug("create_circuit result %s %s", exception, 400) raise BadRequest(str(exception)) from BadRequest if evc.primary_path: try: evc.primary_path.is_valid( evc.uni_a.interface.switch, evc.uni_z.interface.switch, bool(evc.circuit_scheduler), ) except InvalidPath as exception: raise BadRequest( f"primary_path is not valid: {exception}" ) from exception if evc.backup_path: try: evc.backup_path.is_valid( evc.uni_a.interface.switch, evc.uni_z.interface.switch, bool(evc.circuit_scheduler), ) except InvalidPath as exception: raise BadRequest( f"backup_path is not valid: {exception}" ) from exception # verify duplicated evc if self._is_duplicated_evc(evc): result = "The EVC already exists." log.debug("create_circuit result %s %s", result, 409) raise Conflict(result) if ( not evc.primary_path and evc.dynamic_backup_path is False and evc.uni_a.interface.switch != evc.uni_z.interface.switch ): result = "The EVC must have a primary path or allow dynamic paths." log.debug("create_circuit result %s %s", result, 400) raise BadRequest(result) # store circuit in dictionary self.circuits[evc.id] = evc # save circuit self.storehouse.save_evc(evc) # Schedule the circuit deploy self.sched.add(evc) # Circuit has no schedule, deploy now if not evc.circuit_scheduler: with evc.lock: evc.deploy() # Notify users event = KytosEvent( name="kytos.mef_eline.created", content=evc.as_dict() ) self.controller.buffers.app.put(event) result = {"circuit_id": evc.id} status = 201 log.debug("create_circuit result %s %s", result, status) emit_event(self.controller, "created", evc_id=evc.id) return jsonify(result), status
def remove(self): """Remove EVC path and disable it.""" self.remove_current_flows() self.disable() self.sync() emit_event(self._controller, "undeployed", evc_id=self.id)