Esempio n. 1
0
    def find_candidate_subnets(cls,
                               context,
                               network_id,
                               host,
                               service_type,
                               fixed_configured,
                               fixed_ips,
                               distributed_service=False):
        """Find canditate subnets for the network, host, and service_type"""
        query = cls.query_subnets_on_network(context, network_id)
        query = SubnetServiceType.query_filter_service_subnets(
            query, service_type)

        # Select candidate subnets and return them
        if not cls.is_host_set(host):
            if fixed_configured:
                # If fixed_ips in request and host is not known all subnets on
                # the network are candidates. Host/Segment will be validated
                # on port update with binding:host_id set. Allocation _cannot_
                # be deferred as requested fixed_ips would then be lost.
                return cls._query_filter_by_fixed_ips_segment(
                    query,
                    fixed_ips,
                    allow_multiple_segments=distributed_service).all()
            # If the host isn't known, we can't allocate on a routed network.
            # So, exclude any subnets attached to segments.
            return cls._query_exclude_subnets_on_segments(query).all()

        # The host is known. Consider both routed and non-routed networks
        results = cls._query_filter_by_segment_host_mapping(query, host).all()

        # For now, we're using a simplifying assumption that a host will only
        # touch one segment in a given routed network.  Raise exception
        # otherwise.  This restriction may be relaxed as use cases for multiple
        # mappings are understood.
        segment_ids = {
            subnet.segment_id
            for subnet, mapping in results if mapping
        }
        if 1 < len(segment_ids):
            raise segment_exc.HostConnectedToMultipleSegments(
                host=host, network_id=network_id)

        return [subnet for subnet, _mapping in results]
Esempio n. 2
0
    def _ipam_get_subnets(self, context, network_id, host):
        Subnet = models_v2.Subnet
        SegmentHostMapping = segment_svc_db.SegmentHostMapping

        query = self._get_collection_query(context, Subnet)
        query = query.filter(Subnet.network_id == network_id)
        # Note:  This seems redundant, but its not.  It has to cover cases
        # where host is None, ATTR_NOT_SPECIFIED, or '' due to differences in
        # host binding implementations.
        if not validators.is_attr_set(host) or not host:
            query = query.filter(Subnet.segment_id.is_(None))
            return [self._make_subnet_dict(c, context=context) for c in query]

        # A host has been provided.  Consider these two scenarios
        # 1. Not a routed network:  subnets are not on segments
        # 2. Is a routed network:  only subnets on segments mapped to host
        # The following join query returns results for either.  The two are
        # guaranteed to be mutually exclusive when subnets are created.
        query = query.add_entity(SegmentHostMapping)
        query = query.outerjoin(
            SegmentHostMapping,
            and_(Subnet.segment_id == SegmentHostMapping.segment_id,
                 SegmentHostMapping.host == host))
        # Essentially "segment_id IS NULL XNOR host IS NULL"
        query = query.filter(
            or_(
                and_(Subnet.segment_id.isnot(None),
                     SegmentHostMapping.host.isnot(None)),
                and_(Subnet.segment_id.is_(None),
                     SegmentHostMapping.host.is_(None))))

        results = query.all()

        # See if results are empty because the host isn't mapped to a segment
        if not results:
            # Check if it's a routed network (i.e subnets on segments)
            query = self._get_collection_query(context, Subnet)
            query = query.filter(Subnet.network_id == network_id)
            query = query.filter(Subnet.segment_id.isnot(None))
            if query.count() == 0:
                return []
            # It is a routed network but no subnets found for host
            raise segment_exc.HostNotConnectedToAnySegment(
                host=host, network_id=network_id)

        # For now, we're using a simplifying assumption that a host will only
        # touch one segment in a given routed network.  Raise exception
        # otherwise.  This restriction may be relaxed as use cases for multiple
        # mappings are understood.
        segment_ids = {
            subnet.segment_id
            for subnet, mapping in results if mapping
        }
        if 1 < len(segment_ids):
            raise segment_exc.HostConnectedToMultipleSegments(
                host=host, network_id=network_id)

        return [
            self._make_subnet_dict(subnet, context=context)
            for subnet, _mapping in results
        ]