Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
    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
Example #5
0
    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')
Example #6
0
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
Example #7
0
    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')