def checkReservation(self, resource, start_time, end_time): self._checkArgs(resource, start_time, end_time) # check start time is before end time if start_time is not None and end_time is not None and start_time > end_time: raise error.PayloadError( 'Invalid request: Reverse duration (end time before start time)' ) if start_time is not None: # check that start time is not in the past now = datetime.datetime.utcnow() if start_time < now: delta = now - start_time stamp = str(start_time).rsplit('.')[0] variables = [('startTime', start_time.isoformat())] raise error.PayloadError( 'Invalid request: Start time in the past (Startime: %s, Delta: %s)' % (stamp, str(delta)), variables=variables) # check the start time makes sense if start_time > datetime.datetime(2025, 1, 1): raise error.PayloadError( 'Invalid request: Start time after year 2025') for (c_resource, c_start_time, c_end_time) in self.reservations: if resource == c_resource: if self._resourceOverlap(c_start_time, c_end_time, start_time, end_time): raise error.STPUnavailableError( 'Resource %s not available in specified time span' % resource)
def getPort(self, port_id): for port in itertools.chain(self.inbound_ports, self.outbound_ports, self.bidirectional_ports): if port.id_ == port_id: return port # better error message ports = [ p.id_ for p in list(itertools.chain(self.inbound_ports, self.outbound_ports, self.bidirectional_ports)) ] raise error.STPUnavailableError('No port named %s for network %s (ports: %s)' %(port_id, self.id_, str(ports)))
def reserve(self, header, connection_id, global_reservation_id, description, criteria, request_info=None): # return defer.fail( error.InternalNRMError('test reservation failure') ) sd = criteria.service_def if type(sd) is not nsa.Point2PointService: raise ValueError( 'Cannot handle service of type %s, only Point2PointService is currently supported' % type(sd)) # should perhaps verify nsa, but not that important log.msg('Reserve request. Connection ID: %s' % connection_id, system=self.log_system) if connection_id: # if connection id is specified it is not allowed to be used a priori try: conn = yield self._getConnection(connection_id, header.requester_nsa) raise ValueError('GenericBackend cannot handle modify (yet)') except error.ConnectionNonExistentError: pass # expected source_stp = sd.source_stp dest_stp = sd.dest_stp # check network and ports exist if source_stp.network != self.network: raise error.ConnectionCreateError( 'Source network {} does not match the network this NSA is managing ({})' .format(source_stp.network, self.network)) if dest_stp.network != self.network: raise error.ConnectionCreateError( 'Destination network {} does not match network this NSA is managing ({})' .format(dest_stp.network, self.network)) # ensure that ports actually exists if not source_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (source_stp.baseURN(), str(self.nrm_ports.keys()))) if not dest_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (dest_stp.baseURN(), str(self.nrm_ports.keys()))) start_time = criteria.schedule.start_time # or datetime.datetime.utcnow().replace(microsecond=0) + datetime.timedelta(seconds=1) # no start time = now (well, in 1 second) end_time = criteria.schedule.end_time if start_time is not None and end_time is not None: duration = (end_time - start_time).total_seconds() if duration < self.minimum_duration: raise error.ConnectionCreateError( 'Duration too short, minimum duration is %i seconds (%i specified)' % (self.minimum_duration, duration), self.network) nrm_source_port = self.nrm_ports[source_stp.port] nrm_dest_port = self.nrm_ports[dest_stp.port] self._authorize(source_stp.port, dest_stp.port, header, request_info, start_time, end_time) # transit restriction if nrm_source_port.transit_restricted and nrm_dest_port.transit_restricted: raise error.ConnectionCreateError( 'Cannot connect two transit restricted STPs.') # check that we are not connecting two identical stp (hairpin) if source_stp.port == dest_stp.port and source_stp.label == dest_stp.label: raise error.ServiceError('Cannot connect STP %s to itself.' % source_stp) labelType = lambda stp: None if stp.label is None else stp.label.type_ # have the backend check if the ports/labels can be connected # this is needed for cases of cross-label switching like ethernet-mpls encapsulation if hasattr(self.connection_manager, 'canConnect'): if not self.connection_manager.canConnect( source_stp.port, dest_stp.port, source_stp.label, dest_stp.label): raise error.TopologyError('Cannot connect STP %s to %s.' % (source_stp, dest_stp)) elif labelType(source_stp) != labelType(dest_stp): # if backend doesn't implement canConnect, we assume only the same label can be connected (old default) raise error.TopologyError( 'Cannot connect ports with different label types') # now check that the ports have (some of) the specified label values if not nsa.Label.canMatch(nrm_source_port.label, source_stp.label): raise error.TopologyError( 'Source port %s cannot match label set %s' % (nrm_source_port.name, source_stp.label)) if not nsa.Label.canMatch(nrm_dest_port.label, dest_stp.label): raise error.TopologyError( 'Destination port %s cannot match label set %s' % (nrm_dest_port.name, dest_stp.label)) labelEnum = lambda label: [None] if label is None else [ nsa.Label(label.type_, lv) for lv in label.enumerateValues() ] # do the find the label value dance if self.connection_manager.canSwapLabel(labelType( source_stp)) and self.connection_manager.canSwapLabel( labelType(dest_stp)): for lv in labelEnum(source_stp.label): src_resource = self.connection_manager.getResource( source_stp.port, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) src_label = lv break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % source_stp) for lv in labelEnum(dest_stp.label): dst_resource = self.connection_manager.getResource( dest_stp.port, lv) try: self.calendar.checkReservation(dst_resource, start_time, end_time) dst_label = lv break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % dest_stp) # Only add reservations, when src and dest stps are both available self.calendar.addReservation(src_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) else: if source_stp.label is None: label_candidate = dest_stp.label elif dest_stp.label is None: label_candidate = source_stp.label else: try: label_candidate = source_stp.label.intersect( dest_stp.label) except nsa.EmptyLabelSet: raise error.VLANInterchangeNotSupportedError( 'VLAN re-write not supported and no possible label intersection' ) for lv in labelEnum(label_candidate): src_resource = self.connection_manager.getResource( source_stp.port, lv) dst_resource = self.connection_manager.getResource( dest_stp.port, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) self.calendar.checkReservation(dst_resource, start_time, end_time) self.calendar.addReservation(src_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) src_label = lv dst_label = lv break except error.STPUnavailableError: continue else: raise error.STPUnavailableError( 'Link %s and %s not available in specified time span' % (source_stp, dest_stp)) now = datetime.datetime.utcnow() source_target = self.connection_manager.getTarget( source_stp.port, src_label) dest_target = self.connection_manager.getTarget( dest_stp.port, dst_label) if connection_id is None: connection_id = self.connection_manager.createConnectionId( source_target, dest_target) # we should check the schedule here # should we save the requester or provider here? conn = GenericBackendConnections( connection_id=connection_id, revision=0, global_reservation_id=global_reservation_id, description=description, requester_nsa=header.requester_nsa, reserve_time=now, reservation_state=state.RESERVE_START, provision_state=state.RELEASED, lifecycle_state=state.CREATED, data_plane_active=False, source_network=source_stp.network, source_port=source_stp.port, source_label=src_label, dest_network=dest_stp.network, dest_port=dest_stp.port, dest_label=dst_label, start_time=start_time, end_time=end_time, symmetrical=sd.symmetric, directionality=sd.directionality, bandwidth=sd.capacity, allocated=False) yield conn.save() reactor.callWhenRunning(self._doReserve, conn, header.correlation_id) defer.returnValue(connection_id)
def reserve(self, header, connection_id, global_reservation_id, description, criteria): # return defer.fail( error.InternalNRMError('test reservation failure') ) sd = criteria.service_def if type(sd) is not nsa.Point2PointService: raise ValueError( 'Cannot handle service of type %s, only Point2PointService is currently supported' % type(sd)) # should perhaps verify nsa, but not that important log.msg('Reserve request. Connection ID: %s' % connection_id, system=self.log_system) if connection_id: # if connection id is specified it is not allowed to be used a priori try: conn = yield self._getConnection(connection_id, header.requester_nsa) raise ValueError('GenericBackend cannot handle modify (yet)') except error.ConnectionNonExistentError: pass # expected source_stp = sd.source_stp dest_stp = sd.dest_stp # check network and ports exist if source_stp.network != self.network: raise error.ConnectionCreateError( 'Source network does not match network this NSA is managing (%s != %s)' % (source_stp.network, self.network)) if dest_stp.network != self.network: raise error.ConnectionCreateError( 'Destination network does not match network this NSA is managing (%s != %s)' % (dest_stp.network, self.network)) # ensure that ports actually exists if not source_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (source_stp.baseURN(), str(self.nrm_ports.keys()))) if not dest_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (dest_stp.baseURN(), str(self.nrm_ports.keys()))) start_time = criteria.schedule.start_time or datetime.datetime.utcnow( ).replace(microsecond=0) + datetime.timedelta( seconds=1) # no start time = now (well, in 1 second) end_time = criteria.schedule.end_time duration = (end_time - start_time).total_seconds() if duration < self.minimum_duration: raise error.ConnectionCreateError( 'Duration too short, minimum duration is %i seconds (%i specified)' % (self.minimum_duration, duration), self.network) nrm_source_port = self.nrm_ports[source_stp.port] nrm_dest_port = self.nrm_ports[dest_stp.port] # authz check if not nrm_source_port.isAuthorized(header.security_attributes): raise error.UnauthorizedError( 'Request does not have any valid credentials for port %s' % source_stp.baseURN()) if not nrm_dest_port.isAuthorized(header.security_attributes): raise error.UnauthorizedError( 'Request does not have any valid credentials for port %s' % dest_stp.baseURN()) # transit restriction if nrm_source_port.transit_restricted and nrm_dest_port.transit_restricted: raise error.ConnectionCreateError( 'Cannot connect two transit restricted STPs.') # basic label check if source_stp.label is None: raise error.TopologyError('Source STP must specify a label') if dest_stp.label is None: raise error.TopologyError('Destination STP must specify a label') src_label_candidate = source_stp.label dst_label_candidate = dest_stp.label assert src_label_candidate.type_ == dst_label_candidate.type_, 'Cannot connect ports with different label types' # check that we are connecting an stp to itself if source_stp == dest_stp and source_stp.label.singleValue(): raise error.TopologyError('Cannot connect STP %s to itself.' % source_stp) # now check that the ports have (some of) the specified label values if not nsa.Label.canMatch(nrm_source_port.label, src_label_candidate): raise error.TopologyError( 'Source port %s cannot match label set %s' % (nrm_source_port.name, src_label_candidate)) if not nsa.Label.canMatch(nrm_dest_port.label, dst_label_candidate): raise error.TopologyError( 'Destination port %s cannot match label set %s' % (nrm_dest_port.name, dst_label_candidate)) # do the find the label value dance if self.connection_manager.canSwapLabel(src_label_candidate.type_): for lv in src_label_candidate.enumerateValues(): src_resource = self.connection_manager.getResource( source_stp.port, src_label_candidate.type_, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) self.calendar.addReservation(src_resource, start_time, end_time) src_label = nsa.Label(src_label_candidate.type_, str(lv)) break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % source_stp) for lv in dst_label_candidate.enumerateValues(): dst_resource = self.connection_manager.getResource( dest_stp.port, dst_label_candidate.type_, lv) try: self.calendar.checkReservation(dst_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) dst_label = nsa.Label(dst_label_candidate.type_, str(lv)) break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % dest_stp) else: label_candidate = src_label_candidate.intersect( dst_label_candidate) for lv in label_candidate.enumerateValues(): src_resource = self.connection_manager.getResource( source_stp.port, label_candidate.type_, lv) dst_resource = self.connection_manager.getResource( dest_stp.port, label_candidate.type_, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) self.calendar.checkReservation(dst_resource, start_time, end_time) self.calendar.addReservation(src_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) src_label = nsa.Label(label_candidate.type_, str(lv)) dst_label = nsa.Label(label_candidate.type_, str(lv)) break except error.STPUnavailableError: continue else: raise error.STPUnavailableError( 'Link %s and %s not available in specified time span' % (source_stp, dest_stp)) now = datetime.datetime.utcnow() source_target = self.connection_manager.getTarget( source_stp.port, src_label.type_, src_label.labelValue()) dest_target = self.connection_manager.getTarget( dest_stp.port, dst_label.type_, dst_label.labelValue()) if connection_id is None: connection_id = self.connection_manager.createConnectionId( source_target, dest_target) # we should check the schedule here # should we save the requester or provider here? conn = GenericBackendConnections( connection_id=connection_id, revision=0, global_reservation_id=global_reservation_id, description=description, requester_nsa=header.requester_nsa, reserve_time=now, reservation_state=state.RESERVE_START, provision_state=state.RELEASED, lifecycle_state=state.CREATED, data_plane_active=False, source_network=source_stp.network, source_port=source_stp.port, source_label=src_label, dest_network=dest_stp.network, dest_port=dest_stp.port, dest_label=dst_label, start_time=start_time, end_time=end_time, symmetrical=sd.symmetric, directionality=sd.directionality, bandwidth=sd.capacity, allocated=False) yield conn.save() reactor.callWhenRunning(self._doReserve, conn, header.correlation_id) defer.returnValue(connection_id)