<commit_before>"""
Connection abstraction.

Author: <NAME> <<EMAIL>>
Copyright: NORDUnet (2011-2012)
"""
import string
import random
import datetime

from zope.interface import implements

from twisted.python import log
from twisted.internet import defer

from opennsa.interface import INSIProvider, INSIRequester
from opennsa import error, nsa, state, database, constants as cnt



LOG_SYSTEM = 'Aggregator'



def shortLabel(label):
    # create a log friendly string representation of a lbel
    if label is None: # it happens
        return ''

    if '}' in label.type_:
        name = label.type_.split('}',1)[1]
    else:
        name = label.type_
    return name + ':' + label.labelValue()


def _buildErrorMessage(connection_id, action, results):

    # should probably seperate logging somehow
    failures = [ fail for (success, fail) in results if success is False ]
    failure_msgs = [ f.getErrorMessage() for f in failures ]

    log.msg('Connection %s: %i failures' % (connection_id, len(failures)), system=LOG_SYSTEM)
    for msg in failure_msgs:
        log.msg('* Failure: ' + msg, system=LOG_SYSTEM)

    # build the error message to send back
    if len(results) == 1:
        # only one connection, we just return the plain failure
        error_msg = failures[0][1].getErrorMessage()
    else:
        # multiple failures, here we build a more complicated error string
        error_msg = '%i/%i %s failed: %s' % (len(failures), len(results), action, '. '.join(failure_msgs))

    return error_msg


def _createAggregateException(connection_id, action, results, default_error=error.InternalServerError):

    # need to handle multi-errors better, but infrastructure isn't there yet
    failures = [ conn for success,conn in results if not success ]
    if len(failures) == 0:
        # not supposed to happen
        return error.InternalServerError('_createAggregateException called with no failures')
    if len(results) == 1 and len(failures) == 1:
        return failures[0]
    else:
        error_msg = _buildErrorMessage(connection_id, action, results)
        return default_error(error_msg)



class Aggregator:

    implements(INSIProvider, INSIRequester)

    def __init__(self, network, nsa_, topology, route_vectors, parent_requester, provider_registry):
        self.network = network
        self.nsa_ = nsa_
        self.topology = topology
        self.network_topology = self.topology.getNetwork(self.network)
        self.route_vectors = route_vectors

        self.parent_requester   = parent_requester
        self.provider_registry  = provider_registry

        self.conn_prefix = network[:2].upper() + '-T'

        self.reservations       = {} # correlation_id -> info
        self.notification_id    = 0

        # db orm cache, needed to avoid concurrent updates stepping on each other
        self.db_connections = {}
        self.db_sub_connections = {}


    def getNotificationId(self):
        nid = self.notification_id
        self.notification_id += 1
        return nid


    def getProvider(self, nsi_agent_urn):
        return self.provider_registry.getProvider(nsi_agent_urn)


    def getConnection(self, requester_nsa, connection_id):

        # need to do authz here

        def gotResult(connections):
            # we should get 0 or 1 here since connection id is unique
            if len(connections) == 0:
                return defer.fail( error.ConnectionNonExistentError('No connection with id %s' % connection_id) )
            self.db_connections[connection_id] = connections[0]
            return connections[0]

        if connection_id in self.db_connections:
            return defer.succeed(self.db_connections[connection_id])

        d = database.ServiceConnection.findBy(connection_id=connection_id)
        d.addCallback(gotResult)
        return d


    def getConnectionByKey(self, connection_key):

        def gotResult(connections):
            # we should get 0 or 1 here since connection id is unique
            if len(connections) == 0:
                return defer.fail( error.ConnectionNonExistentError('No connection with id %s' % connection_id) )
            conn = connections[0]
            return self.getConnection(conn.requester_nsa, conn.connection_id)

        d = database.ServiceConnection.findBy(id=connection_key)
        d.addCallback(gotResult)
        return d


    def getSubConnection(self, provider_nsa, connection_id):

        def gotResult(connections):
            # we should get 0 or 1 here since provider_nsa + connection id is unique<commit_msg>fix error message in aggregator<commit_after>"""
Connection abstraction.

Author: <NAME> <<EMAIL>>
Copyright: NORDUnet (2011-2012)
"""
import string
import random
import datetime

from zope.interface import implements

from twisted.python import log
from twisted.internet import defer

from opennsa.interface import INSIProvider, INSIRequester
from opennsa import error, nsa, state, database, constants as cnt



LOG_SYSTEM = 'Aggregator'



def shortLabel(label):
    # create a log friendly string representation of a lbel
    if label is None: # it happens
        return ''

    if '}' in label.type_:
        name = label.type_.split('}',1)[1]
    else:
        name = label.type_
    return name + ':' + label.labelValue()


def _buildErrorMessage(connection_id, action, results):

    # should probably seperate logging somehow
    failures = [ fail for (success, fail) in results if success is False ]
    failure_msgs = [ f.getErrorMessage() for f in failures ]

    log.msg('Connection %s: %i failures' % (connection_id, len(failures)), system=LOG_SYSTEM)
    for msg in failure_msgs:
        log.msg('* Failure: ' + msg, system=LOG_SYSTEM)

    # build the error message to send back
    if len(results) == 1:
        # only one connection, we just return the plain failure
        error_msg = failures[0][1].getErrorMessage()
    else:
        # multiple failures, here we build a more complicated error string
        error_msg = '%i/%i %s failed: %s' % (len(failures), len(results), action, '. '.join(failure_msgs))

    return error_msg


def _createAggregateException(connection_id, action, results, default_error=error.InternalServerError):

    # need to handle multi-errors better, but infrastructure isn't there yet
    failures = [ conn for success,conn in results if not success ]
    if len(failures) == 0:
        # not supposed to happen
        return error.InternalServerError('_createAggregateException called with no failures')
    if len(results) == 1 and len(failures) == 1:
        return failures[0]
    else:
        error_msg = _buildErrorMessage(connection_id, action, results)
        return default_error(error_msg)



class Aggregator:

    implements(INSIProvider, INSIRequester)

    def __init__(self, network, nsa_, topology, route_vectors, parent_requester, provider_registry):
        self.network = network
        self.nsa_ = nsa_
        self.topology = topology
        self.network_topology = self.topology.getNetwork(self.network)
        self.route_vectors = route_vectors

        self.parent_requester   = parent_requester
        self.provider_registry  = provider_registry

        self.conn_prefix = network[:2].upper() + '-T'

        self.reservations       = {} # correlation_id -> info
        self.notification_id    = 0

        # db orm cache, needed to avoid concurrent updates stepping on each other
        self.db_connections = {}
        self.db_sub_connections = {}


    def getNotificationId(self):
        nid = self.notification_id
        self.notification_id += 1
        return nid


    def getProvider(self, nsi_agent_urn):
        return self.provider_registry.getProvider(nsi_agent_urn)


    def getConnection(self, requester_nsa, connection_id):

        # need to do authz here

        def gotResult(connections):
            # we should get 0 or 1 here since connection id is unique
            if len(connections) == 0:
                return defer.fail( error.ConnectionNonExistentError('No connection with id %s' % connection_id) )
            self.db_connections[connection_id] = connections[0]
            return connections[0]

        if connection_id in self.db_connections:
            return defer.succeed(self.db_connections[connection_id])

        d = database.ServiceConnection.findBy(connection_id=connection_id)
        d.addCallback(gotResult)
        return d


    def getConnectionByKey(self, connection_key):

        def gotResult(connections):
            # we should get 0 or 1 here since connection id is unique
            if len(connections) == 0:
                return defer.fail( error.ConnectionNonExistentError('No connection with key %s' % connection_key) )
            conn = connections[0]
            return self.getConnection(conn.requester_nsa, conn.connection_id)

        d = database.ServiceConnection.findBy(id=connection_key)
        d.addCallback(gotResult)
        return d


    def getSubConnection(self, provider_nsa, connection_id):

        def gotResult(connections):
            # we should get 0 or 1 here since provider_nsa + connection id is unique
{'fraction_non_alphanumeric': 0.08364271675038218, 'fraction_numerical': 0.006770037126010046, 'mean_word_length': 2.9700910273081926, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7448085', 'n_tokens_mistral': 2644, 'n_tokens_neox': 2491, 'n_words': 755}