def setupBackend(backend_cfg, network_name, nrm_ports, parent_requester): bc = backend_cfg.copy() backend_type = backend_cfg.pop('_backend_type') if backend_type == config.BLOCK_DUD: from opennsa.backends import dud BackendConstructer = dud.DUDNSIBackend # These are not yet ported for the new backend # elif backend_type == config.BLOCK_JUNOS: # from opennsa.backends import junos # return junos.JunOSBackend(network_name, parent_requester, port_map, bc.items()) elif backend_type == config.BLOCK_FORCE10: from opennsa.backends import force10 BackendConstructer = force10.Force10Backend # elif backend_type == config.BLOCK_ARGIA: # from opennsa.backends import argia # return argia.ArgiaBackend(network_name, bc.items()) elif backend_type == config.BLOCK_JUNIPER_EX: from opennsa.backends import juniperex BackendConstructer = juniperex.JuniperEXBackend elif backend_type == config.BLOCK_BROCADE: from opennsa.backends import brocade BackendConstructer = brocade.BrocadeBackend # elif backend_type == config.BLOCK_DELL: # from opennsa.backends import dell # return dell.DellBackend(network_name, bc.items()) elif backend_type == config.BLOCK_NCSVPN: from opennsa.backends import ncsvpn BackendConstructer = ncsvpn.NCSVPNBackend else: raise config.ConfigurationError('No backend specified') b = BackendConstructer(network_name, nrm_ports, parent_requester, bc) return b
def setupTLSContext(vc): # ssl/tls contxt if vc[config.TLS]: from opennsa.opennsaTlsContext import opennsa2WayTlsContext ctx_factory = opennsa2WayTlsContext(vc[config.KEY], vc[config.CERTIFICATE], vc[config.CERTIFICATE_DIR], vc[config.VERIFY_CERT]) elif vc[config.CERTIFICATE_DIR]: # create a context so we can verify https urls if not os.path.isdir(vc[config.CERTIFICATE_DIR]): raise config.ConfigurationError( 'certdir value {} is not a directory'.format( vc[config.CERTIFICATE_DIR])) from opennsa.opennsaTlsContext import opennsaTlsContext ctx_factory = opennsaTlsContext(vc[config.CERTIFICATE_DIR], vc[config.VERIFY_CERT]) else: ctx_factory = None return ctx_factory
def setupBackend(backend_cfg, network_name, nrm_ports, parent_requester): bc = backend_cfg.copy() backend_type = backend_cfg.pop('_backend_type') if backend_type == config.BLOCK_DUD: from opennsa.backends import dud BackendConstructer = dud.DUDNSIBackend elif backend_type == config.BLOCK_JUNOSMX: from opennsa.backends import junosmx BackendConstructer = junosmx.JUNOSMXBackend elif backend_type == config.BLOCK_FORCE10: from opennsa.backends import force10 BackendConstructer = force10.Force10Backend elif backend_type == config.BLOCK_JUNIPER_EX: from opennsa.backends import juniperex BackendConstructer = juniperex.JuniperEXBackend elif backend_type == config.BLOCK_JUNIPER_VPLS: from opennsa.backends import junipervpls BackendConstructer = junipervpls.JuniperVPLSBackend elif backend_type == config.BLOCK_BROCADE: from opennsa.backends import brocade BackendConstructer = brocade.BrocadeBackend elif backend_type == config.BLOCK_NCSVPN: from opennsa.backends import ncsvpn BackendConstructer = ncsvpn.NCSVPNBackend elif backend_type == config.BLOCK_PICA8OVS: from opennsa.backends import pica8ovs BackendConstructer = pica8ovs.Pica8OVSBackend elif backend_type == config.BLOCK_JUNOSSPACE: from opennsa.backends import junosspace BackendConstructer = junosspace.JUNOSSPACEBackend elif backend_type == config.BLOCK_JUNOSEX: from opennsa.backends import junosex BackendConstructer = junosex.JunosEXBackend elif backend_type == config.BLOCK_OESS: from opennsa.backends import oess BackendConstructer = oess.OESSBackend elif backend_type == config.BLOCK_CUSTOM_BACKEND: module_name = backend_cfg.pop('module') try: module = importlib.import_module(module_name) BackendConstructer = module.Backend except Exception as e: log.msg('Failed to load backend {}:\n{}'.format(module_name, e)) raise config.ConfigurationError('Failed to load backend') else: raise config.ConfigurationError('No backend specified') b = BackendConstructer(network_name, nrm_ports, parent_requester, bc) return b
def setupServiceFactory(self): """ This sets up the OpenNSA service and ties together everything in the initialization. There are a lot of things going on, but none of it it particular deep. """ log.msg('OpenNSA service initializing') vc = self.vc now = datetime.datetime.utcnow().replace(microsecond=0) if vc[config.HOST] is None: # guess name if not configured import socket vc[config.HOST] = socket.getfqdn() # database database.setupDatabase(vc[config.DATABASE], vc[config.DATABASE_USER], vc[config.DATABASE_PASSWORD], vc[config.DATABASE_HOST], vc[config.SERVICE_ID_START]) service_endpoints = [] # base names domain_name = vc[config.DOMAIN] # FIXME rename variable to domain nsa_name = domain_name + ':nsa' # base url base_protocol = 'https://' if vc[config.TLS] else 'http://' base_url = base_protocol + vc[config.HOST] + ':' + str(vc[config.PORT]) # nsi endpoint and agent provider_endpoint = base_url + '/NSI/services/CS2' # hardcode for now service_endpoints.append(('Provider', provider_endpoint)) ns_agent = nsa.NetworkServiceAgent(nsa_name, provider_endpoint, 'local') # ssl/tls context ctx_factory = setupTLSContext(vc) # May be None # plugin if vc[config.PLUGIN]: from twisted.python import reflect plugin = reflect.namedAny('opennsa.plugins.%s.plugin' % vc[config.PLUGIN]) else: from opennsa.plugin import BasePlugin plugin = BasePlugin() plugin.init(vc, ctx_factory) # the dance to setup dynamic providers right top_resource = resource.Resource() requester_creator = CS2RequesterCreator( top_resource, None, vc[config.HOST], vc[config.PORT], vc[config.TLS], ctx_factory) # set aggregator later provider_registry = provreg.ProviderRegistry( {cnt.CS2_SERVICE_TYPE: requester_creator.create}) link_vector = linkvector.LinkVector() networks = {} ports = {} # { network : { port : nrmport } } parent_requester = None # parent requester is set later aggr = aggregator.Aggregator(ns_agent, ports, link_vector, parent_requester, provider_registry, vc[config.POLICY], plugin) requester_creator.aggregator = aggr pc = nsi2.setupProvider(aggr, top_resource, ctx_factory=ctx_factory, allowed_hosts=vc.get(config.ALLOWED_HOSTS)) aggr.parent_requester = pc # setup backend(s) - for now we only support one backend_configs = vc['backend'] if len(backend_configs) == 0: log.msg('No backend specified. Running in aggregator-only mode') if not cnt.AGGREGATOR in vc[config.POLICY]: vc[config.POLICY].append(cnt.AGGREGATOR) else: # at least one backend # This is all temporary right now... clean up later for backend_name, b_cfg in backend_configs.items(): if backend_name is None or backend_name == '': raise config.ConfigurationError( 'You need to specify backend name, use [backend:name]') backend_network_name = '{}:{}'.format(domain_name, backend_name) if not config.NRM_MAP_FILE in b_cfg: # move to verify config raise config.ConfigurationError( 'No nrm map specified for backend') backend_nrm_map_file = b_cfg[config.NRM_MAP_FILE] if not os.path.exists( backend_nrm_map_file): # move to verify config raise config.ConfigError( 'nrm map file {} for backend {} does not exists'. format(backend_nrm_map_file, backend_name)) nrm_map = open(backend_nrm_map_file) backend_nrm_ports = nrm.parsePortSpec(nrm_map) link_vector.addLocalNetwork(backend_network_name) for np in backend_nrm_ports: if np.remote_network is not None: link_vector.updateVector( backend_network_name, np.name, {np.remote_network: 1}) # hack for network, cost in np.vectors.items(): link_vector.updateVector(np.name, {network: cost}) # build port map for aggreator to lookup ports.setdefault(backend_network_name, {})[np.name] = np backend_service = setupBackend(b_cfg, backend_network_name, backend_nrm_ports, aggr) networks[backend_network_name] = { 'backend': backend_service, 'nrm_ports': backend_nrm_ports } provider_registry.addProvider(ns_agent.urn(), backend_network_name, backend_service) # fetcher if vc[config.PEERS]: fetcher_service = fetcher.FetcherService(link_vector, networks, vc[config.PEERS], provider_registry, ctx_factory=ctx_factory) fetcher_service.setServiceParent(self) else: log.msg( 'No peers configured, will not be able to do outbound requests (UPA mode)' ) # discovery service opennsa_version = 'OpenNSA-' + version network_urns = [ '{}{}'.format(cnt.URN_OGF_PREFIX, network_name) for network_name in networks ] interfaces = [(cnt.CS2_PROVIDER, provider_endpoint, None), (cnt.CS2_SERVICE_TYPE, provider_endpoint, None)] features = [] if networks: features.append((cnt.FEATURE_UPA, None)) if vc[config.PEERS]: features.append((cnt.FEATURE_AGGREGATOR, None)) # view resource vr = viewresource.ConnectionListResource() top_resource.children[NSI_RESOURCE].putChild('connections', vr) # rest service if vc[config.REST]: rest_url = base_url + '/connections' rest.setupService(aggr, top_resource, vc.get(config.ALLOWED_HOSTS)) service_endpoints.append(('REST', rest_url)) interfaces.append((cnt.OPENNSA_REST, rest_url, None)) for backend_network_name, no in networks.items(): nml_resource_name = '{}.nml.xml'.format(backend_network_name) nml_url = '%s/NSI/%s' % (base_url, nml_resource_name) nml_network = nml.createNMLNetwork(no['nrm_ports'], backend_network_name, backend_network_name) can_swap_label = no['backend'].connection_manager.canSwapLabel( cnt.ETHERNET_VLAN) nml_service = nmlservice.NMLService(nml_network, can_swap_label) top_resource.children[NSI_RESOURCE].putChild( nml_resource_name.encode(), nml_service.resource()) service_endpoints.append(('NML Topology', nml_url)) interfaces.append((cnt.NML_SERVICE_TYPE, nml_url, None)) # discovery service discovery_resource_name = b'discovery.xml' discovery_url = '%s/NSI/%s' % (base_url, discovery_resource_name.decode()) ds = discoveryservice.DiscoveryService(ns_agent.urn(), now, domain_name, opennsa_version, now, network_urns, interfaces, features, provider_registry, link_vector) discovery_resource = ds.resource() top_resource.children[NSI_RESOURCE].putChild(discovery_resource_name, discovery_resource) link_vector.callOnUpdate( lambda: discovery_resource.updateResource(ds.xml())) service_endpoints.append(('Discovery', discovery_url)) # log service urls for service_name, url in service_endpoints: log.msg('{:<12} URL: {}'.format(service_name, url)) factory = server.Site(top_resource) factory.log = httplog.logRequest # default logging is weird, so we do our own return factory, ctx_factory
def startService(self): """ This sets up the OpenNSA service and ties together everything in the initialization. There are a lot of things going on, but none of it it particular deep. """ log.msg('OpenNSA service initializing') vc = self.vc now = datetime.datetime.utcnow().replace(microsecond=0) if vc[config.HOST] is None: # guess name if not configured import socket vc[config.HOST] = socket.getfqdn() # database database.setupDatabase(vc[config.DATABASE], vc[config.DATABASE_USER], vc[config.DATABASE_PASSWORD], vc[config.DATABASE_HOST], vc[config.SERVICE_ID_START]) service_endpoints = [] # base names base_name = vc[config.NETWORK_NAME] network_name = base_name + ':topology' # because we say so nsa_name = base_name + ':nsa' # base url base_protocol = 'https://' if vc[config.TLS] else 'http://' base_url = base_protocol + vc[config.HOST] + ':' + str(vc[config.PORT]) # nsi endpoint and agent provider_endpoint = base_url + '/NSI/services/CS2' # hardcode for now service_endpoints.append(('Provider', provider_endpoint)) ns_agent = nsa.NetworkServiceAgent(nsa_name, provider_endpoint, 'local') # topology nrm_map = open(vc[config.NRM_MAP_FILE]) if vc[ config.NRM_MAP_FILE] is not None else None nrm_ports, nml_network, link_vector = setupTopology( nrm_map, network_name, base_name) # ssl/tls context ctx_factory = setupTLSContext(vc) # May be None # plugin if vc[config.PLUGIN]: from twisted.python import reflect plugin = reflect.namedAny('opennsa.plugins.%s.plugin' % vc[config.PLUGIN]) else: from opennsa.plugin import BasePlugin plugin = BasePlugin() plugin.init(vc, ctx_factory) # the dance to setup dynamic providers right top_resource = resource.Resource() requester_creator = CS2RequesterCreator( top_resource, None, vc[config.HOST], vc[config.PORT], vc[config.TLS], ctx_factory) # set aggregator later provider_registry = provreg.ProviderRegistry( {}, {cnt.CS2_SERVICE_TYPE: requester_creator.create}) aggr = aggregator.Aggregator(network_name, ns_agent, nml_network, link_vector, None, provider_registry, vc[config.POLICY], plugin) # set parent requester later requester_creator.aggregator = aggr pc = nsi2.setupProvider(aggr, top_resource, ctx_factory=ctx_factory, allowed_hosts=vc.get(config.ALLOWED_HOSTS)) aggr.parent_requester = pc # setup backend(s) - for now we only support one backend_configs = vc['backend'] if len(backend_configs) == 0: log.msg('No backend specified. Running in aggregator-only mode') if not cnt.AGGREGATOR in vc[config.POLICY]: vc[config.POLICY].append(cnt.AGGREGATOR) elif len(backend_configs) > 1: raise config.ConfigurationError( 'Only one backend supported for now. Multiple will probably come later.' ) else: # 1 backend if not nrm_ports: raise config.ConfigurationError( 'No NRM Map file specified. Cannot configure a backend without port spec.' ) backend_cfg = backend_configs.values()[0] backend_service = setupBackend(backend_cfg, network_name, nrm_ports, aggr) backend_service.setServiceParent(self) can_swap_label = backend_service.connection_manager.canSwapLabel( cnt.ETHERNET_VLAN) provider_registry.addProvider(ns_agent.urn(), backend_service, [network_name]) # fetcher if vc[config.PEERS]: fetcher_service = fetcher.FetcherService(link_vector, nrm_ports, vc[config.PEERS], provider_registry, ctx_factory=ctx_factory) fetcher_service.setServiceParent(self) else: log.msg( 'No peers configured, will not be able to do outbound requests.' ) # discovery service name = base_name.split(':')[0] if ':' in base_name else base_name opennsa_version = 'OpenNSA-' + version networks = [cnt.URN_OGF_PREFIX + network_name] if nml_network is not None else [] interfaces = [(cnt.CS2_PROVIDER, provider_endpoint, None), (cnt.CS2_SERVICE_TYPE, provider_endpoint, None)] features = [] if nrm_ports: features.append((cnt.FEATURE_UPA, None)) if vc[config.PEERS]: features.append((cnt.FEATURE_AGGREGATOR, None)) # view resource vr = viewresource.ConnectionListResource() top_resource.children['NSI'].putChild('connections', vr) # rest service if vc[config.REST]: rest_url = base_url + '/connections' rest.setupService(aggr, top_resource, vc.get(config.ALLOWED_HOSTS)) service_endpoints.append(('REST', rest_url)) interfaces.append((cnt.OPENNSA_REST, rest_url, None)) # nml topology if nml_network is not None: nml_resource_name = base_name + '.nml.xml' nml_url = '%s/NSI/%s' % (base_url, nml_resource_name) nml_service = nmlservice.NMLService(nml_network, can_swap_label) top_resource.children['NSI'].putChild(nml_resource_name, nml_service.resource()) service_endpoints.append(('NML Topology', nml_url)) interfaces.append((cnt.NML_SERVICE_TYPE, nml_url, None)) # discovery service discovery_resource_name = 'discovery.xml' discovery_url = '%s/NSI/%s' % (base_url, discovery_resource_name) ds = discoveryservice.DiscoveryService(ns_agent.urn(), now, name, opennsa_version, now, networks, interfaces, features, provider_registry, link_vector) discovery_resource = ds.resource() top_resource.children['NSI'].putChild(discovery_resource_name, discovery_resource) link_vector.callOnUpdate( lambda: discovery_resource.updateResource(ds.xml())) service_endpoints.append(('Discovery', discovery_url)) # print service urls for service_name, url in service_endpoints: log.msg('{:<12} URL: {}'.format(service_name, url)) factory = server.Site(top_resource) factory.log = httplog.logRequest # default logging is weird, so we do our own if vc[config.TLS]: internet.SSLServer(vc[config.PORT], factory, ctx_factory).setServiceParent(self) else: internet.TCPServer(vc[config.PORT], factory).setServiceParent(self) # do not start sub-services until we have started this one twistedservice.MultiService.startService(self) log.msg('OpenNSA service started')
def parsePortSpec(source): # Parse the entries like the following: ## type name remote label bandwidth interface authz # #ethernet ps - vlan:1780-1783 1000 em0 [email protected] #ethernet netherlight netherlight#nordunet-(in|out) vlan:1780-1783 1000 em1 - #ethernet uvalight uvalight#nordunet-(in|out) vlan:1780-1783 1000 em2 nsa=aruba.net:nsa # Line starting with # and blank lines should be ignored assert isinstance(source, file) or isinstance( source, StringIO.StringIO), 'Topology source must be file or StringIO instance' nrm_ports = [] for line in source: line = line.strip() if not line or line.startswith('#'): continue tokens = [t for t in line.split(' ') if t != ''] if len(tokens) != 7: raise NRMSpecificationError( 'Invalid number of entries for entry: %s' % line) port_type, port_name, remote_spec, label_spec, bandwidth, interface, authz = tokens if not port_type in PORT_TYPES: raise error.TopologyError('Port type %s is not a valid port type' % port_type) remote_network, remote_port, in_suffix, out_suffix = _parseRemoteSpec( remote_spec) label = _parseLabelSpec(label_spec) try: bandwidth = int(bandwidth) except ValueError as e: raise NRMSpecificationError('Invalid bandwidth: %s' % str(e)) if port_type == cnt.NRM_ETHERNET: if remote_network is None: remote_port = None remote_in = None remote_out = None else: if not in_suffix or not out_suffix: raise NRMSpecificationError( 'Suffix not defined for bidirectional port %s' % port_name) remote_port = remote_network + ':' + remote_port remote_in = remote_port + in_suffix remote_out = remote_port + out_suffix else: raise AssertionError('do not know what to with port of type %s' % port_type) # these are more than auth attributes, but thats what they where for initially authz_attributes = [] link_vectors = {} transit_restricted = False if authz != '-': for aa in authz.split(','): if '=' in aa: #authz_attributes.append( nsa.SecurityAttribute(*aa.split('=',2)) ) ak, av = aa.split('=', 2) if ak in AUTH_ATTRIBUTES: authz_attributes.append(nsa.SecurityAttribute(ak, av)) elif ak in PATH_ATTRIBUTES: if not '@' in av: raise config.ConfigurationError( 'Invalid path value: %s' % av) network, weight = av.split('@', 1) link_vectors[network] = int(weight) else: raise config.ConfigurationError( 'Invalid attribute: %s' % aa) elif aa in ATTRIBUTES and aa == cnt.NRM_RESTRICTTRANSIT: transit_restricted = True else: raise config.ConfigurationError('Invalid attribute: %s' % aa) nrm_ports.append( NRMPort(port_type, port_name, remote_network, remote_port, remote_in, remote_out, label, bandwidth, interface, authz_attributes, link_vectors, transit_restricted)) return nrm_ports
def startService(self): """ This sets up the OpenNSA service and ties together everything in the initialization. There are a lot of things going on, but none of it it particular deep. """ log.msg('OpenNSA service initializing') vc = self.vc now = datetime.datetime.utcnow().replace(microsecond=0) if vc[config.HOST] is None: # guess name if not configured import socket vc[config.HOST] = socket.getfqdn() # database database.setupDatabase(vc[config.DATABASE], vc[config.DATABASE_USER], vc[config.DATABASE_PASSWORD]) # base names base_name = vc[config.NETWORK_NAME] network_name = base_name + ':topology' # because we say so nsa_name = base_name + ':nsa' # url stuffs base_protocol = 'https://' if vc[config.TLS] else 'http://' base_url = base_protocol + vc[config.HOST] + ':' + str(vc[config.PORT]) # nsi agent provider_endpoint = base_url + '/NSI/services/CS2' # hardcode for now ns_agent = nsa.NetworkServiceAgent(nsa_name, provider_endpoint, 'local') # topology nrm_ports = nrm.parsePortSpec( open( vc[config.NRM_MAP_FILE] ) ) network_topology = nml.createNMLNetwork(nrm_ports, network_name, base_name) # route vectors link_vector = linkvector.LinkVector( [ network_name ] ) # hack in link vectors manually, since we don't have a mechanism for updating them automatically for np in nrm_ports: if np.remote_network is not None: link_vector.updateVector(np.name, { np.remote_network : 1 } ) # hack for network, cost in np.vectors.items(): link_vector.updateVector(np.name, { network : cost }) # ssl/tls contxt if vc[config.TLS]: from opennsa import ctxfactory ctx_factory = ctxfactory.ContextFactory(vc[config.KEY], vc[config.CERTIFICATE], vc[config.CERTIFICATE_DIR], vc[config.VERIFY_CERT]) elif os.path.isdir(vc[config.CERTIFICATE_DIR]): # we can at least create a context from opennsa import ctxfactory ctx_factory = ctxfactory.RequestContextFactory(vc[config.CERTIFICATE_DIR], vc[config.VERIFY_CERT]) else: ctx_factory = None # plugin if vc[config.PLUGIN]: from twisted.python import reflect plugin = reflect.namedAny('opennsa.plugins.%s.plugin' % vc[config.PLUGIN]) else: from opennsa.plugin import BasePlugin plugin = BasePlugin() plugin.init(vc, ctx_factory) # the dance to setup dynamic providers right top_resource = resource.Resource() requester_creator = CS2RequesterCreator(top_resource, None, vc[config.HOST], vc[config.PORT], vc[config.TLS], ctx_factory) # set aggregator later provider_registry = provreg.ProviderRegistry({}, { cnt.CS2_SERVICE_TYPE : requester_creator.create } ) aggr = aggregator.Aggregator(network_topology.id_, ns_agent, network_topology, link_vector, None, provider_registry, vc[config.POLICY], plugin ) # set parent requester later requester_creator.aggregator = aggr pc = nsi2.setupProvider(aggr, top_resource, ctx_factory=ctx_factory, allowed_hosts=vc.get(config.ALLOWED_HOSTS)) aggr.parent_requester = pc # setup backend(s) - for now we only support one backend_configs = vc['backend'] if len(backend_configs) > 1: raise config.ConfigurationError('Only one backend supported for now. Multiple will probably come later.') backend_cfg = backend_configs.values()[0] backend_service = setupBackend(backend_cfg, network_topology.id_, nrm_ports, aggr) backend_service.setServiceParent(self) can_swap_label = backend_service.connection_manager.canSwapLabel(cnt.ETHERNET_VLAN) provider_registry.addProvider(ns_agent.urn(), backend_service, [ network_topology.id_ ] ) # fetcher if vc[config.PEERS]: fetcher_service = fetcher.FetcherService(link_vector, nrm_ports, vc[config.PEERS], provider_registry, ctx_factory=ctx_factory) fetcher_service.setServiceParent(self) # wire up the http stuff discovery_resource_name = 'discovery.xml' nml_resource_name = base_name + '.nml.xml' nml_resource_url = '%s/NSI/%s' % (base_url, nml_resource_name) # discovery service name = base_name.split(':')[0] if ':' in base_name else base_name opennsa_version = 'OpenNSA-' + version networks = [ cnt.URN_OGF_PREFIX + network_name ] interfaces = [ ( cnt.CS2_PROVIDER, provider_endpoint, None), ( cnt.CS2_SERVICE_TYPE, provider_endpoint, None), (cnt.NML_SERVICE_TYPE, nml_resource_url, None) ] features = [ (cnt.FEATURE_AGGREGATOR, None), (cnt.FEATURE_UPA, None) ] ds = discoveryservice.DiscoveryService(ns_agent.urn(), now, name, opennsa_version, now, networks, interfaces, features, provider_registry, link_vector) discovery_resource = ds.resource() top_resource.children['NSI'].putChild(discovery_resource_name, discovery_resource) link_vector.callOnUpdate( lambda : discovery_resource.updateResource ( ds.xml() )) # view resource vr = viewresource.ConnectionListResource(aggr) top_resource.children['NSI'].putChild('connections', vr) # topology nml_service = nmlservice.NMLService(network_topology, can_swap_label) top_resource.children['NSI'].putChild(nml_resource_name, nml_service.resource() ) log.msg('Provider URL: %s' % provider_endpoint ) log.msg('Discovery URL: %s/NSI/%s' % (base_url, discovery_resource_name) ) log.msg('Topology URL: %s' % (nml_resource_url) ) factory = server.Site(top_resource) factory.log = httplog.logRequest # default logging is weird, so we do our own if vc[config.TLS]: internet.SSLServer(vc[config.PORT], factory, ctx_factory).setServiceParent(self) else: internet.TCPServer(vc[config.PORT], factory).setServiceParent(self) # do not start sub-services until we have started this one twistedservice.MultiService.startService(self) log.msg('OpenNSA service started')