예제 #1
0
    def select_subnet(self,
                      context,
                      net_id,
                      ip_address,
                      segment_id,
                      subnet_ids=None,
                      **filters):
        LOG.info("Selecting subnet(s) - (Step 2 of 3) [{0}]".format(
            utils.pretty_kwargs(network_id=net_id,
                                ip_address=ip_address,
                                segment_id=segment_id,
                                subnet_ids=subnet_ids,
                                ip_version=filters.get("ip_version"))))

        # TODO(mdietz): Invert the iterator and the session, should only be
        #               one subnet per attempt. We should also only be fetching
        #               the subnet and usage when we need to. Otherwise
        #               we're locking every subnet for a segment, and once
        #               we stop locking, we're looking at stale data.
        with context.session.begin():
            for subnet, ips_in_subnet in self._select_subnet(
                    context, net_id, ip_address, segment_id, subnet_ids,
                    **filters):
                if subnet is None:
                    continue
                ipnet = netaddr.IPNetwork(subnet["cidr"])
                LOG.info("Trying subnet ID: {0} - CIDR: {1}".format(
                    subnet["id"], subnet["_cidr"]))

                if not self._ip_in_subnet(subnet, subnet_ids, ipnet,
                                          ip_address):
                    continue

                if self._should_mark_subnet_full(context, subnet, ipnet,
                                                 ip_address, ips_in_subnet):
                    LOG.info("Marking subnet {0} as full".format(subnet["id"]))
                    updated = db_api.subnet_update_set_full(context, subnet)

                    # Ensure the session is aware of the changes to the subnet
                    if updated:
                        context.session.refresh(subnet)
                    continue

                if not ip_address and subnet["ip_version"] == 4:
                    auto_inc = db_api.subnet_update_next_auto_assign_ip
                    updated = auto_inc(context, subnet)

                    if updated:
                        context.session.refresh(subnet)
                    else:
                        # This means the subnet was marked full
                        # while we were checking out policies.
                        # Fall out and go back to the outer retry
                        # loop.
                        return

                LOG.info("Subnet {0} - {1} {2} looks viable, "
                         "returning".format(subnet["id"], subnet["_cidr"],
                                            subnet["next_auto_assign_ip"]))
                return subnet
예제 #2
0
파일: ipam.py 프로젝트: roaet/quark
    def select_subnet(self, context, net_id, ip_address, segment_id,
                      subnet_ids=None, **filters):
        LOG.info("Selecting subnet(s) - (Step 2 of 3) [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, ip_address=ip_address,
                                segment_id=segment_id, subnet_ids=subnet_ids,
                                ip_version=filters.get("ip_version"))))

        # TODO(mdietz): Invert the iterator and the session, should only be
        #               one subnet per attempt. We should also only be fetching
        #               the subnet and usage when we need to. Otherwise
        #               we're locking every subnet for a segment, and once
        #               we stop locking, we're looking at stale data.
        with context.session.begin():
            for subnet, ips_in_subnet in self._select_subnet(context, net_id,
                                                             ip_address,
                                                             segment_id,
                                                             subnet_ids,
                                                             **filters):
                if subnet is None:
                    continue
                ipnet = netaddr.IPNetwork(subnet["cidr"])
                LOG.info("Trying subnet ID: {0} - CIDR: {1}".format(
                    subnet["id"], subnet["_cidr"]))

                if not self._ip_in_subnet(subnet, subnet_ids, ipnet,
                                          ip_address):
                    continue

                if self._should_mark_subnet_full(context, subnet, ipnet,
                                                 ip_address, ips_in_subnet):
                    LOG.info("Marking subnet {0} as full".format(subnet["id"]))
                    updated = db_api.subnet_update_set_full(context, subnet)

                    # Ensure the session is aware of the changes to the subnet
                    if updated:
                        context.session.refresh(subnet)
                    continue

                if not ip_address and subnet["ip_version"] == 4:
                    auto_inc = db_api.subnet_update_next_auto_assign_ip
                    updated = auto_inc(context, subnet)

                    if updated:
                        context.session.refresh(subnet)
                    else:
                        # This means the subnet was marked full
                        # while we were checking out policies.
                        # Fall out and go back to the outer retry
                        # loop.
                        return

                LOG.info("Subnet {0} - {1} {2} looks viable, "
                         "returning".format(subnet["id"], subnet["_cidr"],
                                            subnet["next_auto_assign_ip"]))
                return subnet
예제 #3
0
파일: test_api.py 프로젝트: xroot88/quark
 def test_subnet_set_full(self):
     cidr4 = "0.0.0.0/30"  # 2 bits
     net4 = netaddr.IPNetwork(cidr4)
     with self._fixtures([self._create_models(cidr4, 4, net4[0])]) as net:
         subnet = db_api.subnet_find(self.context,
                                     network_id=net['id'],
                                     scope=db_api.ALL)[0]
         with self.context.session.begin():
             updated = db_api.subnet_update_set_full(self.context, subnet)
             self.context.session.refresh(subnet)
             self.assertTrue(updated)
             self.assertEqual(subnet["next_auto_assign_ip"], -1)
예제 #4
0
 def test_subnet_set_full(self):
     cidr4 = "0.0.0.0/30"  # 2 bits
     net4 = netaddr.IPNetwork(cidr4)
     with self._fixtures([
         self._create_models(cidr4, 4, net4[0])
     ]) as net:
         subnet = db_api.subnet_find(self.context, network_id=net['id'],
                                     scope=db_api.ALL)[0]
         with self.context.session.begin():
             updated = db_api.subnet_update_set_full(self.context, subnet)
             self.context.session.refresh(subnet)
             self.assertTrue(updated)
             self.assertEqual(subnet["next_auto_assign_ip"], -1)
예제 #5
0
    def select_subnet(self, context, net_id, ip_address, segment_id,
                      subnet_ids=None, **filters):
        LOG.info("Selecting subnet(s) - (Step 2 of 3) [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, ip_address=ip_address,
                                segment_id=segment_id, subnet_ids=subnet_ids,
                                ip_version=filters.get("ip_version"))))

        with context.session.begin():
            subnets = db_api.subnet_find_ordered_by_most_full(
                context, net_id, segment_id=segment_id, scope=db_api.ALL,
                subnet_id=subnet_ids, **filters)

            if not subnets:
                LOG.info("No subnets found given the search criteria!")

            for subnet, ips_in_subnet in subnets:
                ipnet = netaddr.IPNetwork(subnet["cidr"])
                LOG.info("Trying subnet ID: {0} - CIDR: {1}".format(
                    subnet["id"], subnet["_cidr"]))
                if ip_address:
                    requested_ip = netaddr.IPAddress(ip_address)
                    if ipnet.version == 4 and requested_ip.version != 4:
                        requested_ip = requested_ip.ipv4()
                    if requested_ip not in ipnet:
                        if subnet_ids is not None:
                            LOG.info("Requested IP {0} not in subnet {1}, "
                                     "retrying".format(str(requested_ip),
                                                       str(ipnet)))
                            raise q_exc.IPAddressNotInSubnet(
                                ip_addr=ip_address, subnet_id=subnet["id"])
                        continue

                ip_policy = None
                if not ip_address:
                    # Policies don't prevent explicit assignment, so we only
                    # need to check if we're allocating a new IP
                    ip_policy = subnet.get("ip_policy")

                policy_size = ip_policy["size"] if ip_policy else 0

                if ipnet.size > (ips_in_subnet + policy_size - 1):
                    if not ip_address and subnet["ip_version"] == 4:
                        ip = subnet["next_auto_assign_ip"]
                        # NOTE(mdietz): When atomically updated, this probably
                        #               doesn't need the lower bounds check but
                        #               I'm not comfortable removing it yet.
                        updated = 0
                        if ip < subnet["first_ip"] or ip > subnet["last_ip"]:
                            LOG.info("Marking subnet {0} as full".format(
                                subnet["id"]))
                            updated = db_api.subnet_update_set_full(context,
                                                                    subnet)
                        else:
                            auto_inc = db_api.subnet_update_next_auto_assign_ip
                            updated = auto_inc(context, subnet)

                        if updated:
                            context.session.refresh(subnet)
                        else:
                            # This means the subnet was marked full
                            # while we were checking out policies.
                            # Fall out and go back to the outer retry
                            # loop.
                            return

                    LOG.info("Subnet {0} - {1} {2} looks viable, "
                             "returning".format(subnet["id"], subnet["_cidr"],
                                                subnet["next_auto_assign_ip"]))
                    return subnet
                else:
                    LOG.info("Marking subnet {0} as full".format(subnet["id"]))
                    db_api.subnet_update_set_full(context, subnet)