예제 #1
0
    def bind_port(self, port_context):
        """Set binding for a valid segment

        """
        host_name = port_context.host
        elements = list()
        try:
            # Append to empty list to add as much elements as possible
            # in the case it raises an exception
            elements.extend(self._fetch_elements_by_host(host_name))
        except Exception:
            LOG.exception(
                _LE('Error fetching elements for host %(host_name)r.'),
                {'host_name': host_name},
                exc_info=1)

        if not elements:
            # In case it wasn't able to find any network topology element
            # for given host then it uses the legacy OVS one keeping the old
            # behaviour
            LOG.warning(
                _LW('Using legacy OVS network topology element for port '
                    'binding for host: %(host_name)r.'),
                {'host_name': host_name})

            # Imported here to avoid cyclic module dependencies
            from networking_odl.ml2 import ovsdb_topology
            elements = [ovsdb_topology.OvsdbNetworkTopologyElement()]

        # TODO(Federico Ressi): in the case there are more candidate virtual
        # switches instances for the same host it choses one for binding
        # port. As there isn't any know way to perform this selection it
        # selects a VIF type that is valid for all switches that have
        # been found and a VIF type valid for all them. This has to be improved
        for vif_type in self.valid_vif_types:
            vif_type_is_valid_for_all = True
            for element in elements:
                if vif_type not in element.valid_vif_types:
                    # it is invalid for at least one element: discard it
                    vif_type_is_valid_for_all = False
                    break

            if vif_type_is_valid_for_all:
                # This is the best VIF type valid for all elements
                LOG.debug(
                    "Found VIF type %(vif_type)r valid for all network "
                    "topology elements for host %(host_name)r.", {
                        'vif_type': vif_type,
                        'host_name': host_name
                    })

                for element in elements:
                    # It assumes that any element could be good for given host
                    # In most of the cases I expect exactely one element for
                    # every compute host
                    try:
                        return element.bind_port(port_context, vif_type,
                                                 self._vif_details)

                    except Exception:
                        LOG.exception(
                            _LE('Network topology element has failed binding '
                                'port:\n%(element)s'),
                            {'element': element.to_json()})

        LOG.error(
            _LE('Unable to bind port element for given host and valid VIF '
                'types:\n'
                '\thostname: %(host_name)s\n'
                '\tvalid VIF types: %(valid_vif_types)s'), {
                    'host_name': host_name,
                    'valid_vif_types': ', '.join(self.valid_vif_types)
                })
예제 #2
0
    def fetch_all(self, keys, timeout):
        # this mean now in numbers
        current_clock = time.clock()
        # this is the moment in the future in which new entries will expires
        new_entries_timeout = current_clock + timeout
        # entries to be fetched because missing or expired
        new_entries = collections.OrderedDict()
        # all entries missing or expired
        missing = collections.OrderedDict()
        # captured error for the case a problem has to be reported
        cause_exc_info = None

        for key in keys:
            entry = self._entries.get(key)
            if entry is None or entry.is_expired(current_clock) or entry.error:
                # this entry has to be fetched
                new_entries[key] = missing[key] =\
                    self.create_new_entry(new_entries_timeout)
            elif entry.values:
                # Yield existing entry
                for value in entry.values:
                    yield key, value
            else:
                # This entry is not expired and there were no error where it
                # has been fetch. Therefore we accept that there are no values
                # for given key until it expires. This is going to produce a
                # KeyError if it is still missing at the end of this function.
                missing[key] = entry

        if missing:
            if new_entries:
                # Fetch some entries and update the cache
                try:
                    new_entry_keys = tuple(new_entries)
                    for key, value in self._fetch_all(new_entry_keys):
                        entry = new_entries.get(key)
                        if entry:
                            # Add fresh new value
                            entry.add_value(value)
                        else:
                            # This key was not asked, but we take it in any
                            # way. "Noli equi dentes inspicere donati."
                            new_entries[key] = entry = self.create_new_entry(
                                new_entries_timeout, value)

                # pylint: disable=broad-except
                except Exception:
                    # Something has gone wrong: update and yield what got until
                    # now before raising any error
                    cause_exc_info = sys.exc_info()
                    LOG.warning(
                        _LW('Error fetching values for keys: %r'),
                        ', '.join(repr(k) for k in new_entry_keys),
                        exc_info=cause_exc_info)

                # update the cache with new fresh entries
                self._entries.update(new_entries)

            missing_keys = []
            for key, entry in six.iteritems(missing):
                if entry.values:
                    # yield entries that was missing before
                    for value in entry.values:
                        # Yield just fetched entry
                        yield key, value
                else:
                    if cause_exc_info:
                        # mark this entry as failed
                        entry.error = cause_exc_info
                    # after all this entry is still without any value
                    missing_keys.append(key)

            if missing_keys:
                # After all some entry is still missing, probably because the
                # key was invalid. It's time to raise an error.
                missing_keys = tuple(missing_keys)
                if not cause_exc_info:
                    # Search for the error cause in missing entries
                    for key in missing_keys:
                        error = self._entries[key].error
                        if error:
                            # A cached entry for which fetch method produced an
                            # error will produce the same error if fetch method
                            # fails to fetch it again without giving any error
                            # Is this what we want?
                            break

                    else:
                        # If the cause of the problem is not knwow then
                        # probably keys were wrong
                        message = 'Invalid keys: {!r}'.format(
                            ', '.join(missing_keys))
                        error = KeyError(message)

                    try:
                        raise error
                    except KeyError:
                        cause_exc_info = sys.exc_info()

                raise CacheFetchError(
                    missing_keys=missing_keys, cause_exc_info=cause_exc_info)
    def bind_port(self, port_context):
        """Set binding for a valid segment

        """
        host_name = port_context.host
        elements = list()
        try:
            # Append to empty list to add as much elements as possible
            # in the case it raises an exception
            elements.extend(self._fetch_elements_by_host(host_name))
        except Exception:
            LOG.exception(
                _LE('Error fetching elements for host %(host_name)r.'),
                {'host_name': host_name}, exc_info=1)

        if not elements:
            # In case it wasn't able to find any network topology element
            # for given host then it uses the legacy OVS one keeping the old
            # behaviour
            LOG.warning(
                _LW('Using legacy OVS network topology element for port '
                    'binding for host: %(host_name)r.'),
                {'host_name': host_name})

            # Imported here to avoid cyclic module dependencies
            from networking_odl.ml2 import ovsdb_topology
            elements = [ovsdb_topology.OvsdbNetworkTopologyElement()]

        # TODO(Federico Ressi): in the case there are more candidate virtual
        # switches instances for the same host it choses one for binding
        # port. As there isn't any know way to perform this selection it
        # selects a VIF type that is valid for all switches that have
        # been found and a VIF type valid for all them. This has to be improved
        for vif_type in self.valid_vif_types:
            vif_type_is_valid_for_all = True
            for element in elements:
                if vif_type not in element.valid_vif_types:
                    # it is invalid for at least one element: discard it
                    vif_type_is_valid_for_all = False
                    break

            if vif_type_is_valid_for_all:
                # This is the best VIF type valid for all elements
                LOG.debug(
                    "Found VIF type %(vif_type)r valid for all network "
                    "topology elements for host %(host_name)r.",
                    {'vif_type': vif_type, 'host_name': host_name})

                for element in elements:
                    # It assumes that any element could be good for given host
                    # In most of the cases I expect exactely one element for
                    # every compute host
                    try:
                        return element.bind_port(
                            port_context, vif_type, self._vif_details)

                    except Exception:
                        LOG.exception(
                            _LE('Network topology element has failed binding '
                                'port:\n%(element)s'),
                            {'element': element.to_json()})

        LOG.error(
            _LE('Unable to bind port element for given host and valid VIF '
                'types:\n'
                '\thostname: %(host_name)s\n'
                '\tvalid VIF types: %(valid_vif_types)s'),
            {'host_name': host_name,
             'valid_vif_types': ', '.join(self.valid_vif_types)})
예제 #4
0
    def fetch_all(self, keys, timeout):
        # this mean now in numbers
        current_clock = time.clock()
        # this is the moment in the future in which new entries will expires
        new_entries_timeout = current_clock + timeout
        # entries to be fetched because missing or expired
        new_entries = collections.OrderedDict()
        # all entries missing or expired
        missing = collections.OrderedDict()
        # captured error for the case a problem has to be reported
        cause_exc_info = None

        for key in keys:
            entry = self._entries.get(key)
            if entry is None or entry.is_expired(current_clock) or entry.error:
                # this entry has to be fetched
                new_entries[key] = missing[key] =\
                    self.create_new_entry(new_entries_timeout)
            elif entry.values:
                # Yield existing entry
                for value in entry.values:
                    yield key, value
            else:
                # This entry is not expired and there were no error where it
                # has been fetch. Therefore we accept that there are no values
                # for given key until it expires. This is going to produce a
                # KeyError if it is still missing at the end of this function.
                missing[key] = entry

        if missing:
            if new_entries:
                # Fetch some entries and update the cache
                try:
                    new_entry_keys = tuple(new_entries)
                    for key, value in self._fetch_all(new_entry_keys):
                        entry = new_entries.get(key)
                        if entry:
                            # Add fresh new value
                            entry.add_value(value)
                        else:
                            # This key was not asked, but we take it in any
                            # way. "Noli equi dentes inspicere donati."
                            new_entries[key] = entry = self.create_new_entry(
                                new_entries_timeout, value)

                # pylint: disable=broad-except
                except Exception:
                    # Something has gone wrong: update and yield what got until
                    # now before raising any error
                    cause_exc_info = sys.exc_info()
                    LOG.warning(_LW('Error fetching values for keys: %r'),
                                ', '.join(repr(k) for k in new_entry_keys),
                                exc_info=cause_exc_info)

                # update the cache with new fresh entries
                self._entries.update(new_entries)

            missing_keys = []
            for key, entry in six.iteritems(missing):
                if entry.values:
                    # yield entries that was missing before
                    for value in entry.values:
                        # Yield just fetched entry
                        yield key, value
                else:
                    if cause_exc_info:
                        # mark this entry as failed
                        entry.error = cause_exc_info
                    # after all this entry is still without any value
                    missing_keys.append(key)

            if missing_keys:
                # After all some entry is still missing, probably because the
                # key was invalid. It's time to raise an error.
                missing_keys = tuple(missing_keys)
                if not cause_exc_info:
                    # Search for the error cause in missing entries
                    for key in missing_keys:
                        error = self._entries[key].error
                        if error:
                            # A cached entry for which fetch method produced an
                            # error will produce the same error if fetch method
                            # fails to fetch it again without giving any error
                            # Is this what we want?
                            break

                    else:
                        # If the cause of the problem is not knwow then
                        # probably keys were wrong
                        message = 'Invalid keys: {!r}'.format(
                            ', '.join(missing_keys))
                        error = KeyError(message)

                    try:
                        raise error
                    except KeyError:
                        cause_exc_info = sys.exc_info()

                raise CacheFetchError(missing_keys=missing_keys,
                                      cause_exc_info=cause_exc_info)