def testLabelRangeMultiReservation(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1781-1783')) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1781-1783')) criteria = nsa.Criteria( 0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 100, 'Bidirectional', False, None)) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer self.header.newCorrelationId() yield self.provider.reserveCommit(self.header, acid) yield self.requester.reserve_commit_defer self.requester.reserve_defer = defer.Deferred() self.requester.reserve_commit_defer = defer.Deferred() self.header.newCorrelationId() acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer self.header.newCorrelationId() yield self.provider.reserveCommit(self.header, acid2) yield self.requester.reserve_commit_defer
def setUp(self): self.clock = task.Clock() tcf = os.path.expanduser('~/.opennsa-test.json') tc = json.load( open(tcf) ) ncs_config = { config.NCS_SERVICES_URL : tc['ncs-url'], config.NCS_USER : tc['ncs-user'], config.NCS_PASSWORD : tc['ncs-password'] } self.requester = common.DUDRequester() self.backend = ncsvpn.NCSVPNBackend('Test', self.sr, self.requester, ncs_config) self.backend.scheduler.clock = self.clock self.backend.startService() database.setupDatabase(tc['database'], tc['database-user'], tc['database-password'], host=tc['hostname']) self.requester_nsa = nsa.NetworkServiceAgent('test-requester', 'http://example.org/nsa-test-requester') self.provider_nsa = nsa.NetworkServiceAgent('test-provider', 'http://example.org/nsa-test-provider') source_stp = nsa.STP('ncs', 'hel:ge-1/0/1', labels=[ nsa.Label(nml.ETHERNET_VLAN, '100-102') ] ) dest_stp = nsa.STP('ncs', 'sto:ge-1/0/1', labels=[ nsa.Label(nml.ETHERNET_VLAN, '101-104') ] ) start_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=2) end_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=30) bandwidth = 200 self.service_params = nsa.ServiceParameters(start_time, end_time, source_stp, dest_stp, bandwidth)
def testReserveTimeout(self): # these need to be constructed such that there is only one label option source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer self.clock.advance(self.backend.TPC_TIMEOUT + 1) header, cid, notification_id, timestamp, timeout_value, org_cid, org_nsa = yield self.requester.reserve_timeout_defer self.failUnlessEquals(cid, acid) self.requester.reserve_defer = defer.Deferred() # new criteria start_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=2) end_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=6) schedule = nsa.Schedule(start_time, end_time) criteria = nsa.Criteria(0, schedule, nsa.Point2PointService(source_stp, dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) ) # try to reserve the same resources acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer
def testContainedLabelsIntersection(self): self.failUnlessEquals( nsa.Label('', '80-89').intersect(nsa.Label('', '81-82')).enumerateValues(), [81, 82])
def testReserveAbort(self): # these need to be constructed such that there is only one label option source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782')) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782')) criteria = nsa.Criteria( 0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None)) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveAbort(self.header, acid) header, cid = yield self.requester.reserve_abort_defer self.requester.reserve_defer = defer.Deferred() # try to reserve the same resources acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer
def testLabelValueEnumeration(self): self.assertEquals(nsa.Label('', '1-2,3').enumerateValues(), [1, 2, 3]) self.assertEquals(nsa.Label('', '1-3,2').enumerateValues(), [1, 2, 3]) self.assertEquals( nsa.Label('', '1-3,3,1-2').enumerateValues(), [1, 2, 3]) self.assertEquals( nsa.Label('', '2-4,8,1-3').enumerateValues(), [1, 2, 3, 4, 8])
def testSlowActivate(self): # key here is that end time is passed when activation is done start_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=2) end_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=4) schedule = nsa.Schedule(start_time, end_time) source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1780')) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1780')) criteria = nsa.Criteria( 0, schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None)) def setupLink(connection_id, src, dst, bandwidth): d = defer.Deferred() reactor.callLater(2, d.callback, None) return d # make activation fail via monkey patching self.backend.connection_manager.setupLink = setupLink self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer self.failUnlessEqual(cid, acid) yield self.provider.reserveCommit(self.header, cid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEqual(cid, acid) self.failUnlessEqual(active, True) self.failUnlessEqual(consistent, True) self.requester.data_plane_change_defer = defer.Deferred() self.clock.advance(2) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEqual(cid, acid) self.failUnlessEqual(active, False) yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer
def testReserveFailAndLabelSwapEnabled(self): # When you try to reserve a circuit using a labelSwap enabled backend and the dest_stp appers to be in use, # the src stp reservation never gets removed from the calendar self.assertTrue(self.backend.connection_manager.canSwapLabel(cnt.ETHERNET_VLAN),"DUD is not able to swapLabels") # Construct a valid circuit source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) #We shouldn't have reservations in the calendar right now self.assertEquals(len(self.backend.calendar.reservations), 0, "Reservations size is %s should be 0" % len(self.backend.calendar.reservations)) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer # reset deferred for reservation self.requester.reserve_defer = defer.Deferred() # 2 reservations, for source_stp and dest_stp self.assertEquals(len(self.backend.calendar.reservations), 2, "Reservations size is %s should be 2" % len(self.backend.calendar.reservations)) #Construct a second circuit, with the same dest_stp source_stp2 = nsa.STP(self.network,self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1781')) criteria2 = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp2, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() try: acid2 = yield self.provider.reserve(self.header, None, None, None, criteria2) header2, cid2, gid2, desc2, sp2 = yield self.requester.reserve_defer except error.STPUnavailableError as e: pass # reset deferred for reservation self.requester.reserve_defer = defer.Deferred() # The second reserve request failed, so we should have the original 2 reservations in the calendar self.assertEquals(len(self.backend.calendar.reservations), 2, "Reservations size is %s should be 2" % len(self.backend.calendar.reservations)) # terminate the connection yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer for stp in [source_stp2,dest_stp,source_stp]: try: res = self.backend.connection_manager.getResource(stp.port, stp.label) resource_is_available = self.backend.calendar.checkReservation(res, self.schedule.start_time,self.schedule.end_time) except error.STPUnavailableError as e: self.fail("STP %s should be available" % res)
def testPruningEnd(self): ndn_link = nsa.Link( nsa.STP('nordu.net:2013:topology', 'funet', nsa.Label('vlan', '2031-2035')), nsa.STP('nordu.net:2013:topology', 'surfnet', nsa.Label('vlan', '2-4094')) ) sfn_link = nsa.Link( nsa.STP('surfnet.nl:1990:production7', 'nordunet', nsa.Label('vlan', '2-4094')), nsa.STP('surfnet.nl:1990:production7', '19523', nsa.Label('vlan', '2077')) ) path = [ ndn_link, sfn_link ] pruned_path = pruner.pruneLabels(path) self.assertEquals(pruned_path[0].dst_stp.label.labelValue(), '2077') self.assertEquals(pruned_path[1].src_stp.label.labelValue(), '2077')
def testInvalidNetworkReservation(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP('NoSuchNetwork:topology', 'whatever', nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, 'Bidirectional', False, None) ) self.header.newCorrelationId() try: yield self.provider.reserve(self.header, None, None, None, criteria) self.fail('Should have raised TopologyError') except (error.ConnectionCreateError, error.STPResolutionError): # we raise ConnectionCreateError in backends, and STPResolutionError in aggregator pass # expected
def testLabelIntersection(self): l12 = nsa.Label('', '1,2') l123 = nsa.Label('', '1,2,3') l234 = nsa.Label('', '2-4') l48 = nsa.Label('', '4-8') self.assertEquals(l12.intersect(l12).values, [(1, 2)]) self.assertEquals(l12.intersect(l123).values, [(1, 2)]) self.assertEquals(l12.intersect(l234).values, [(2, 2)]) self.assertEquals(l123.intersect(l234).values, [(2, 3)]) self.assertEquals(l234.intersect(l48).values, [(4, 4)]) self.assertRaises(nsa.EmptyLabelSet, l12.intersect, l48)
def testHairpinConnection(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1783') ) sd = nsa.Point2PointService(source_stp, dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) criteria = nsa.Criteria(0, self.schedule, sd) self.header.newCorrelationId() try: yield self.provider.reserve(self.header, None, None, None, criteria) self.fail('Should have raised ServceError / TopologyError') except error.ServiceError: pass # expected - hairpin except error.TopologyError: pass # expected - double vlan assignment
def testHairpinConnectionAllowed(self): self.provider.policies.append(cnt.ALLOW_HAIRPIN) source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1783') ) sd = nsa.Point2PointService(source_stp, dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) criteria = nsa.Criteria(0, self.schedule, sd) self.header.newCorrelationId() try: acid = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer except Exception as e: self.fail('Should not have raised exception: %s' % str(e))
def parseLabel(label_part): if not '=' in label_part: raise error.PayloadError('No = in urn label part (%s)' % label_part) label_short_type, label_value = label_part.split('=') try: label_type = LABEL_MAP[label_short_type] except KeyError: raise error.PayloadError('Label type %s not recognized') return nsa.Label(label_type, label_value)
def _createSTP(stp_arg): # no generic label stuff for now if '#' in stp_arg: stp_desc, vlan = stp_arg.split('#') network, port = stp_desc.rsplit(':',1) label = nsa.Label(cnt.ETHERNET_VLAN, vlan) else: network, port = stp_arg.rsplit(':',1) label = None return nsa.STP(network, port, label)
def _parseLabelSpec(label_spec): if not ':' in label_spec: raise error.TopologyError('Invalid label description: %s' % label_spec) label_type_alias, label_range = label_spec.split(':', 1) try: label_type = LABEL_TYPES[label_type_alias] except KeyError: raise error.TopologyError( 'Label type %s does not map to proper label.' % label_type_alias) return nsa.Label(label_type, label_range) # range is parsed in nsa.Label
def testLabelParsing(self): self.assertEquals(nsa.Label('', '1,2').values, [(1, 2)]) self.assertEquals(nsa.Label('', '1,2,3').values, [(1, 3)]) self.assertEquals(nsa.Label('', '1-2,3').values, [(1, 3)]) self.assertEquals(nsa.Label('', '1-3,2').values, [(1, 3)]) self.assertEquals(nsa.Label('', '1-3,3,1-2').values, [(1, 3)]) self.assertEquals(nsa.Label('', '2-4,8,1-3').values, [(1, 4), (8, 8)])
def testPartialSwapPathfinding(self): # make bonaire and dominica capable of swapping label self.networks[1].canSwapLabel = lambda _: True self.networks[3].canSwapLabel = lambda _: True paths = self.topology.findPaths(ARUBA_PS, BONAIRE_PS, 100) self.assertEquals(len(paths), 3) fp = paths[0] self.assertEquals(len(fp), 2) # aruba - bonaire self.assertEquals([l.network for l in fp], [ARUBA_NETWORK, BONAIRE_NETWORK]) tpl = nsa.Label(cnt.ETHERNET_VLAN, '1781-1789') self.assertEquals(fp[0].src_label, tpl) self.assertEquals(fp[0].dst_label, tpl) self.assertEquals(fp[1].src_label, tpl) self.assertEquals(fp[1].dst_label, tpl) del fp, tpl sp = paths[1] self.assertEquals(len(sp), 3) # aruba - dominica - bonaire self.assertEquals([l.network for l in sp], [ARUBA_NETWORK, DOMINICA_NETWORK, BONAIRE_NETWORK]) tpl = nsa.Label(cnt.ETHERNET_VLAN, '1781-1789') ipl = nsa.Label(cnt.ETHERNET_VLAN, '1781-1782') self.assertEquals(sp[0].src_label, tpl) self.assertEquals(sp[0].dst_label, tpl) self.assertEquals(sp[1].src_label, tpl) self.assertEquals(sp[1].dst_label, ipl) self.assertEquals(sp[2].src_label, ipl) self.assertEquals(sp[2].dst_label, tpl) del sp, tpl, ipl tp = paths[2] self.assertEquals(len(tp), 4) # aruba - dominica - curacao - bonaire self.assertEquals([l.network for l in tp], [ ARUBA_NETWORK, DOMINICA_NETWORK, CURACAO_NETWORK, BONAIRE_NETWORK ]) tpl = nsa.Label(cnt.ETHERNET_VLAN, '1781-1789') ipl = nsa.Label(cnt.ETHERNET_VLAN, '1781-1789') jpl = nsa.Label(cnt.ETHERNET_VLAN, '1783-1786') self.assertEquals(tp[0].src_label, tpl) self.assertEquals(tp[0].dst_label, ipl) self.assertEquals(tp[1].src_label, ipl) self.assertEquals(tp[1].dst_label, jpl) self.assertEquals(tp[2].src_label, jpl) self.assertEquals(tp[2].dst_label, jpl) self.assertEquals(tp[3].src_label, jpl) self.assertEquals(tp[3].dst_label, tpl)
def testReserveTerminateReReserve(self): # Tamas Varga found a bug where calendar isn't probably cleanup up on reserve+terminate # This reproduces the the issue # these need to be constructed such that there is only one label option source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer # reset deferred for reservation self.requester.reserve_defer = defer.Deferred() # terminate the connection yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer # try to reserve the same resources acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer
def testNoSwapPathfinding(self): paths = self.topology.findPaths(ARUBA_PS, BONAIRE_PS, 100) self.assertEquals(len(paths), 3) first_path = paths[0] self.assertEquals(len(first_path), 2) # aruba - bonaire self.assertEquals([l.network for l in first_path], [ARUBA_NETWORK, BONAIRE_NETWORK]) fpl = nsa.Label(cnt.ETHERNET_VLAN, '1781-1789') for link in first_path: self.assertEquals(link.src_label, fpl) self.assertEquals(link.dst_label, fpl) second_path = paths[1] self.assertEquals(len(second_path), 3) # aruba - dominica - bonaire self.assertEquals([l.network for l in second_path], [ARUBA_NETWORK, DOMINICA_NETWORK, BONAIRE_NETWORK]) spl = nsa.Label(cnt.ETHERNET_VLAN, '1781-1782') for link in second_path: self.assertEquals(link.src_label, spl) self.assertEquals(link.dst_label, spl) third_path = paths[2] self.assertEquals(len(third_path), 4) # aruba - dominica - curacao - bonaire self.assertEquals([l.network for l in third_path], [ ARUBA_NETWORK, DOMINICA_NETWORK, CURACAO_NETWORK, BONAIRE_NETWORK ]) tpl = nsa.Label(cnt.ETHERNET_VLAN, '1783-1786') for link in third_path: self.assertEquals(link.src_label, tpl) self.assertEquals(link.dst_label, tpl)
def testDoubleReserve(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1781') ) p2p = nsa.Point2PointService(source_stp, self.dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) criteria = nsa.Criteria(0, self.schedule, p2p) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer self.requester.reserve_defer = defer.Deferred() # new defer for new reserve request try: acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) self.fail('Should have raised STPUnavailableError') except error.STPUnavailableError: pass # we expect this
def _createSTP(stp_arg): if not ':' in stp_arg: raise usage.UsageError('No ":" in stp, invalid format (see docs/cli.md)') if '#' in stp_arg: stp_desc, label_desc = stp_arg.split('#') network, port = stp_desc.rsplit(':',1) if not '=' in label_desc: raise usage.UsageError('No "=" in stp label, invalid format (see docs/cli.md)') label_type,label_value = label_desc.split("=") label = nsa.Label(LABEL_MAP[label_type],label_value) # FIXME need good error message if label type doesn't exist else: network, port = stp_arg.rsplit(':',1) label = None return nsa.STP(network, port, label)
def pruneLabels(path): """ Some networks does not support underspecified STPs and VLAN rewrites so we help them out a bit. """ for idx, link in enumerate(path): if any( [ n in link.src_stp.network for n in NETWORKS ] ): liv = link.src_stp.label.intersect(link.dst_stp.label) lnv = nsa.Label(liv.type_, liv.labelValue()) link.src_stp.label = lnv link.dst_stp.label = lnv if idx > 0: prev_link = path[idx-1] prev_link.dst_stp.label = lnv if idx < len(path) - 1: next_link = path[idx+1] next_link.src_stp.label = lnv return path
def testPruningStart(self): sfn_link = nsa.Link( nsa.STP('surfnet.nl:1990:production7', 'ps', nsa.Label('vlan', '1784')), nsa.STP('surfnet.nl:1990:production7', 'sara-ndn1', nsa.Label('vlan', '1780-1799')) ) ndn_link = nsa.Link( nsa.STP('nordu.net:2013:topology', 'surfnet', nsa.Label('vlan', '1784-1789')), nsa.STP('nordu.net:2013:topology', 'deic1', nsa.Label('vlan', '1784-1789')) ) dec_link = nsa.Link( nsa.STP('deic.dk:2013:topology', 'ndn1', nsa.Label('vlan', '1784-1789')), nsa.STP('deic.dk:2013:topology', 'ps', nsa.Label('vlan', '1784')) ) path = [ sfn_link, ndn_link, dec_link ] pruned_path = pruner.pruneLabels(path) self.assertEquals(pruned_path[0].dst_stp.label.labelValue(), '1784') self.assertEquals(pruned_path[1].src_stp.label.labelValue(), '1784')
def parseNMLPort(nml_port): assert nml_port.tag in ( NML_PORT, NML_PORTGROUP ), 'Port tag name must be nml:Port or nml:PortGroup, not (%s)' % nml_port.tag port_id = _baseName(nml_port.attrib[ID]) port_name = None label = None remote_port = None for pe in nml_port: if pe.tag == NML_NAME: port_name = pe.text elif pe.tag in (NML_LABEL, NML_LABELGROUP): label_type = pe.attrib[LABEL_TYPE] label_value = pe.text label = nsa.Label(label_type, label_value) elif pe.tag == NML_RELATION: if pe.attrib[TYPE] == NML_ISALIAS: port_alias = pe[0].attrib[ID] remote_port = _baseName(port_alias) else: log.msg('Unknown nml relation type %s, ignoring' % pe.attrib[TYPE], system=LOG_SYSTEM) else: log.msg('Unknown port element %s, ignoring' % pe, system=LOG_SYSTEM) # make up a name if none is specified if port_name is None: port_name = port_id.split(':')[-1] port = nml.Port(port_id, port_name, label, remote_port) return port
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)
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)
from StringIO import StringIO from twisted.trial import unittest from opennsa import nsa, error, constants as cnt from opennsa.topology import nml, nrm from . import topology LABEL = nsa.Label(cnt.ETHERNET_VLAN, '1781-1789') ARUBA_NETWORK = 'aruba:topology' BONAIRE_NETWORK = 'bonaire:topology' CURACAO_NETWORK = 'curacao:topology' DOMINICA_NETWORK = 'dominica:topology' ARUBA_PS = nsa.STP(ARUBA_NETWORK, 'ps', LABEL) BONAIRE_PS = nsa.STP(BONAIRE_NETWORK, 'ps', LABEL) CURACAO_PS = nsa.STP(CURACAO_NETWORK, 'ps', LABEL) class TopologyTest(unittest.TestCase): def setUp(self): an, _ = nrm.parseTopologySpec(StringIO(topology.ARUBA_TOPOLOGY), ARUBA_NETWORK) bn, _ = nrm.parseTopologySpec(StringIO(topology.BONAIRE_TOPOLOGY), BONAIRE_NETWORK) cn, _ = nrm.parseTopologySpec(StringIO(topology.CURACAO_TOPOLOGY), CURACAO_NETWORK) dn, _ = nrm.parseTopologySpec(StringIO(topology.DOMINICA_TOPOLOGY), DOMINICA_NETWORK)
def make(self, values): return nsa.Label(*values)
class GenericProviderTest: # basic values we need when testing base = 'aruba' network = base + ':topology' source_port = 'ps' dest_port = 'bon' source_stp = nsa.STP(network, source_port, nsa.Label(cnt.ETHERNET_VLAN, '1781-1782') ) dest_stp = nsa.STP(network, dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782-1783') ) bandwidth = 200 @defer.inlineCallbacks def testBasicUsage(self): self.header.newCorrelationId() response_cid = yield self.provider.reserve(self.header, None, None, None, self.criteria) header, confirm_cid, gid, desc, criteria = yield self.requester.reserve_defer self.failUnlessEquals(response_cid, confirm_cid, 'Connection Id from response and confirmation differs') yield self.provider.reserveCommit(header, response_cid) yield self.requester.reserve_commit_defer yield self.provider.terminate(self.header, response_cid) @defer.inlineCallbacks def testProvisionPostTerminate(self): self.header.newCorrelationId() cid = yield self.provider.reserve(self.header, None, None, None, self.criteria) header, confirm_cid, gid, desc, criteria = yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, cid) yield self.requester.reserve_commit_defer yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer try: yield self.provider.provision(self.header, cid) self.fail('Should have raised ConnectionGoneError') except error.ConnectionGoneError: pass # expected @defer.inlineCallbacks def testStartTimeInPast(self): start_time = datetime.datetime.utcnow() - datetime.timedelta(seconds=60) criteria = nsa.Criteria(0, nsa.Schedule(start_time, self.end_time), self.sd) self.header.newCorrelationId() try: yield self.provider.reserve(self.header, None, None, None, criteria) self.fail('Should have raised PayloadError') # Error type is somewhat debatable, but this what we use except error.PayloadError: pass # expected @defer.inlineCallbacks def testNoStartTime(self): start_time = None criteria = nsa.Criteria(0, nsa.Schedule(start_time, self.end_time), self.sd) self.header.newCorrelationId() cid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, cid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEquals(active, True) @defer.inlineCallbacks def testNoEndTime(self): end_time = None criteria = nsa.Criteria(0, nsa.Schedule(self.start_time, end_time), self.sd) self.header.newCorrelationId() cid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, cid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEquals(active, True) @defer.inlineCallbacks def testNoStartOrEndTime(self): criteria = nsa.Criteria(0, nsa.Schedule(None, None), self.sd) self.header.newCorrelationId() cid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, cid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEquals(active, True) @defer.inlineCallbacks def testHairpinConnection(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1783') ) sd = nsa.Point2PointService(source_stp, dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) criteria = nsa.Criteria(0, self.schedule, sd) self.header.newCorrelationId() try: yield self.provider.reserve(self.header, None, None, None, criteria) self.fail('Should have raised ServceError / TopologyError') except error.ServiceError: pass # expected - hairpin except error.TopologyError: pass # expected - double vlan assignment @defer.inlineCallbacks def testProvisionWithoutCommit(self): self.header.newCorrelationId() cid = yield self.provider.reserve(self.header, None, None, None, self.criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer self.clock.advance(self.backend.TPC_TIMEOUT + 1) header, cid, notification_id, timestamp, timeout_value, org_cid, org_nsa = yield self.requester.reserve_timeout_defer try: # provision without committing first... yield self.provider.provision(self.header, cid) except error.ConnectionError: pass # expected @defer.inlineCallbacks def testProvisionUsage(self): self.header.newCorrelationId() cid = yield self.provider.reserve(self.header, None, None, None, self.criteria) yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, cid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) yield self.requester.provision_defer yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer @defer.inlineCallbacks def testProvisionReleaseNoStartEndTime(self): schedule = nsa.Schedule(None, None) criteria = nsa.Criteria(0, schedule, nsa.Point2PointService(self.source_stp, self.dest_stp, 200, 'Bidirectional', False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, acid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, acid) yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEquals(active, True) self.requester.data_plane_change_defer = defer.Deferred() yield self.provider.release(self.header, acid) yield self.requester.release_defer header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEquals(active, False) yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer @defer.inlineCallbacks def testProvisionReleaseUsage(self): self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, self.criteria) yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, acid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, acid) yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEquals(active, True) self.requester.data_plane_change_defer = defer.Deferred() yield self.provider.release(self.header, acid) yield self.requester.release_defer header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEquals(active, False) yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer @defer.inlineCallbacks def testInvalidNetworkReservation(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP('NoSuchNetwork:topology', 'whatever', nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, 'Bidirectional', False, None) ) self.header.newCorrelationId() try: yield self.provider.reserve(self.header, None, None, None, criteria) self.fail('Should have raised TopologyError') except (error.ConnectionCreateError, error.STPResolutionError): # we raise ConnectionCreateError in backends, and STPResolutionError in aggregator pass # expected @defer.inlineCallbacks def testLabelRangeMultiReservation(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1781-1783') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1781-1783') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 100, 'Bidirectional', False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer self.header.newCorrelationId() yield self.provider.reserveCommit(self.header, acid) yield self.requester.reserve_commit_defer self.requester.reserve_defer = defer.Deferred() self.requester.reserve_commit_defer = defer.Deferred() self.header.newCorrelationId() acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer self.header.newCorrelationId() yield self.provider.reserveCommit(self.header, acid2) yield self.requester.reserve_commit_defer @defer.inlineCallbacks def testDoubleReserve(self): source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1781') ) p2p = nsa.Point2PointService(source_stp, self.dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) criteria = nsa.Criteria(0, self.schedule, p2p) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer self.requester.reserve_defer = defer.Deferred() # new defer for new reserve request try: acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) self.fail('Should have raised STPUnavailableError') except error.STPUnavailableError: pass # we expect this @defer.inlineCallbacks def testProvisionNonExistentConnection(self): self.header.newCorrelationId() try: yield self.provider.provision(self.header, '1234') self.fail('Should have raised ConnectionNonExistentError') except error.ConnectionNonExistentError: pass # expected @defer.inlineCallbacks def testQuerySummary(self): self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, 'gid-123', 'desc2', self.criteria) yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, acid) yield self.requester.reserve_commit_defer self.header.newCorrelationId() yield self.provider.querySummary(self.header, connection_ids = [ acid ] ) header, reservations = yield self.requester.query_summary_defer self.failUnlessEquals(len(reservations), 1) ci = reservations[0] self.failUnlessEquals(ci.connection_id, acid) self.failUnlessEquals(ci.global_reservation_id, 'gid-123') self.failUnlessEquals(ci.description, 'desc2') self.failUnlessEquals(ci.requester_nsa, self.requester_agent.urn()) self.failUnlessEquals(len(ci.criterias), 1) crit = ci.criterias[0] src_stp = crit.service_def.source_stp dst_stp = crit.service_def.dest_stp self.failUnlessEquals(src_stp.network, self.network) self.failUnlessEquals(src_stp.port, self.source_port) self.failUnlessEquals(src_stp.label.type_, cnt.ETHERNET_VLAN) self.failUnlessIn(src_stp.label.labelValue(), ('1781', '1782') ) self.failUnlessEquals(dst_stp.network, self.network) self.failUnlessEquals(dst_stp.port, self.dest_port) self.failUnlessEquals(dst_stp.label.type_, cnt.ETHERNET_VLAN) self.failUnlessIn(dst_stp.label.labelValue(), ('1782', '1783') ) self.failUnlessEqual(crit.service_def.capacity, self.bandwidth) self.failUnlessEqual(crit.revision, 0) from opennsa import state rsm, psm, lsm, dps = ci.states self.failUnlessEquals(rsm, state.RESERVE_START) self.failUnlessEquals(psm, state.RELEASED) self.failUnlessEquals(lsm, state.CREATED) self.failUnlessEquals(dps[:2], (False, 0) ) # we cannot really expect a consistent result for consistent here @defer.inlineCallbacks def testActivation(self): self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, self.criteria) header, cid, gid, desc, sc = yield self.requester.reserve_defer self.failUnlessEqual(cid, acid) yield self.provider.reserveCommit(self.header, acid) cid = yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, acid) cid = yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.requester.data_plane_change_defer = defer.Deferred() # need a new one for deactivate self.failUnlessEqual(cid, acid) self.failUnlessEqual(active, True) self.failUnlessEqual(consistent, True) #yield self.provider.release(self.header, cid) #cid = yield self.requester.release_defer yield self.provider.terminate(self.header, acid) cid = yield self.requester.terminate_defer @defer.inlineCallbacks def testReserveAbort(self): # these need to be constructed such that there is only one label option source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveAbort(self.header, acid) header, cid = yield self.requester.reserve_abort_defer self.requester.reserve_defer = defer.Deferred() # try to reserve the same resources acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer @defer.inlineCallbacks def testNoEndtimeAbort(self): # these need to be constructed such that there is only one label option source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) end_time = None criteria = nsa.Criteria(0, nsa.Schedule(self.start_time, end_time), nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveAbort(self.header, acid) header, cid = yield self.requester.reserve_abort_defer self.requester.reserve_defer = defer.Deferred() # try to reserve the same resources acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer @defer.inlineCallbacks def testReserveTerminateReReserve(self): # Tamas Varga found a bug where calendar isn't probably cleanup up on reserve+terminate # This reproduces the the issue # these need to be constructed such that there is only one label option source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer # reset deferred for reservation self.requester.reserve_defer = defer.Deferred() # terminate the connection yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer # try to reserve the same resources acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) yield self.requester.reserve_defer @defer.inlineCallbacks def testReserveFailAndLabelSwapEnabled(self): # When you try to reserve a circuit using a labelSwap enabled backend and the dest_stp appers to be in use, # the src stp reservation never gets removed from the calendar self.assertTrue(self.backend.connection_manager.canSwapLabel(cnt.ETHERNET_VLAN),"DUD is not able to swapLabels") # Construct a valid circuit source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) #We shouldn't have reservations in the calendar right now self.assertEquals(len(self.backend.calendar.reservations), 0, "Reservations size is %s should be 0" % len(self.backend.calendar.reservations)) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer # reset deferred for reservation self.requester.reserve_defer = defer.Deferred() # 2 reservations, for source_stp and dest_stp self.assertEquals(len(self.backend.calendar.reservations), 2, "Reservations size is %s should be 2" % len(self.backend.calendar.reservations)) #Construct a second circuit, with the same dest_stp source_stp2 = nsa.STP(self.network,self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1781')) criteria2 = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp2, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() try: acid2 = yield self.provider.reserve(self.header, None, None, None, criteria2) header2, cid2, gid2, desc2, sp2 = yield self.requester.reserve_defer except error.STPUnavailableError as e: pass # reset deferred for reservation self.requester.reserve_defer = defer.Deferred() # The second reserve request failed, so we should have the original 2 reservations in the calendar self.assertEquals(len(self.backend.calendar.reservations), 2, "Reservations size is %s should be 2" % len(self.backend.calendar.reservations)) # terminate the connection yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer for stp in [source_stp2,dest_stp,source_stp]: try: res = self.backend.connection_manager.getResource(stp.port, stp.label) resource_is_available = self.backend.calendar.checkReservation(res, self.schedule.start_time,self.schedule.end_time) except error.STPUnavailableError as e: self.fail("STP %s should be available" % res) @defer.inlineCallbacks def testReserveTimeout(self): # these need to be constructed such that there is only one label option source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1782') ) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer self.clock.advance(self.backend.TPC_TIMEOUT + 1) header, cid, notification_id, timestamp, timeout_value, org_cid, org_nsa = yield self.requester.reserve_timeout_defer self.failUnlessEquals(cid, acid) self.requester.reserve_defer = defer.Deferred() # new criteria start_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=2) end_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=6) schedule = nsa.Schedule(start_time, end_time) criteria = nsa.Criteria(0, schedule, nsa.Point2PointService(source_stp, dest_stp, self.bandwidth, cnt.BIDIRECTIONAL, False, None) ) # try to reserve the same resources acid2 = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer @defer.inlineCallbacks def testSlowActivate(self): # key here is that end time is passed when activation is done start_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=2) end_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=4) schedule = nsa.Schedule(start_time, end_time) source_stp = nsa.STP(self.network, self.source_port, nsa.Label(cnt.ETHERNET_VLAN, '1780') ) dest_stp = nsa.STP(self.network, self.dest_port, nsa.Label(cnt.ETHERNET_VLAN, '1780') ) criteria = nsa.Criteria(0, schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) def setupLink(connection_id, src, dst, bandwidth): d = defer.Deferred() reactor.callLater(2, d.callback, None) return d # make activation slow via monkey patching self.backend.connection_manager.setupLink = setupLink self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer self.failUnlessEqual(cid, acid) yield self.provider.reserveCommit(self.header, cid) yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEqual(cid, acid) self.failUnlessEqual(active, True) self.failUnlessEqual(consistent, True) self.requester.data_plane_change_defer = defer.Deferred() self.clock.advance(2) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.failUnlessEqual(cid, acid) self.failUnlessEqual(active, False) yield self.provider.terminate(self.header, cid) yield self.requester.terminate_defer testSlowActivate.timeout = 15 testSlowActivate.skip = 'Too slow to be a regular test (uses reactor calls and real timings)' @defer.inlineCallbacks def testFaultyActivate(self): # make actication fail via monkey patching self.backend.connection_manager.setupLink = lambda cid, src, dst, bw : defer.fail(error.InternalNRMError('Link setup failed')) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, self.criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, acid) header, cid = yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) header, cid = yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, event, info, ex = yield self.requester.error_event_defer self.failUnlessEquals(event, 'activateFailed') self.failUnlessEquals(cid, acid) @defer.inlineCallbacks def testFaultyDeactivate(self): # make actication fail via monkey patching self.backend.connection_manager.teardownLink = lambda cid, src, dst, bw : defer.fail(error.InternalNRMError('Link teardown failed')) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, self.criteria) header, cid, gid, desc, sp = yield self.requester.reserve_defer yield self.provider.reserveCommit(self.header, cid) header, cid = yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, cid) header, cid = yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.requester.data_plane_change_defer = defer.Deferred() self.clock.advance(11) header, cid, nid, timestamp, event, info, ex = yield self.requester.error_event_defer self.failUnlessEquals(event, 'deactivateFailed') self.failUnlessEquals(cid, acid) @defer.inlineCallbacks def testIdenticalPortSTPs(self): source_stp = nsa.STP(self.network, 'eth1', None) dest_stp = nsa.STP(self.network, 'eth1', None) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() try: acid = yield self.provider.reserve(self.header, None, None, None, criteria) self.fail("Should have gotten service error for identical ports") except error.ServiceError: pass # expected @defer.inlineCallbacks def testInvalidRewrite(self): source_stp = nsa.STP(self.network, 'eth1', None) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, self.dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() try: acid = yield self.provider.reserve(self.header, None, None, None, criteria) self.fail("Should have gotten topology error ") except error.NSIError: pass # expected @defer.inlineCallbacks def testPortSTPs(self): source_stp = nsa.STP(self.network, 'eth1', None) dest_stp = nsa.STP(self.network, 'eth2', None) criteria = nsa.Criteria(0, self.schedule, nsa.Point2PointService(source_stp, dest_stp, 200, cnt.BIDIRECTIONAL, False, None) ) self.header.newCorrelationId() acid = yield self.provider.reserve(self.header, None, None, None, criteria) header, cid, gid, desc, sc = yield self.requester.reserve_defer self.failUnlessEqual(cid, acid) yield self.provider.reserveCommit(self.header, acid) cid = yield self.requester.reserve_commit_defer yield self.provider.provision(self.header, acid) cid = yield self.requester.provision_defer self.clock.advance(3) header, cid, nid, timestamp, dps = yield self.requester.data_plane_change_defer active, version, consistent = dps self.requester.data_plane_change_defer = defer.Deferred() # need a new one for deactivate self.failUnlessEqual(cid, acid) self.failUnlessEqual(active, True) self.failUnlessEqual(consistent, True) #yield self.provider.release(self.header, cid) #cid = yield self.requester.release_defer yield self.provider.terminate(self.header, acid) cid = yield self.requester.terminate_defer