Beispiel #1
0
    def test_address_not_in_cidr(self):
        self.network_db = self.insert_network()
        self.subnet_v4_db = self.insert_subnet(
            self.network_db, "192.168.0.0/24")
        self.ip_address_v4 = netaddr.IPAddress("192.168.1.1")
        ip_address_db = self.insert_ip_address(self.ip_address_v4,
                                               self.network_db,
                                               self.subnet_v4_db)
        self.transaction = self.insert_transaction()
        ip_kwargs = {
            "network_id": self.network_db["id"],
            "reuse_after": self.REUSE_AFTER,
            "deallocated": True,
            "version": 4,
        }
        reallocated = db_api.ip_address_reallocate(
            self.context,
            {"transaction_id": self.transaction.id},
            **ip_kwargs)
        self.assertTrue(reallocated)

        updated_address = db_api.ip_address_reallocate_find(
            self.context, self.transaction.id)
        self.assertIsNone(updated_address)

        self.context.session.flush()
        self.assertIsNone(db_api.ip_address_find(self.context,
                                                 id=ip_address_db.id,
                                                 scope=db_api.ONE))
    def test_subnet_do_not_use(self):
        self.network_db = self.insert_network()
        self.subnet_v4_db = self.insert_subnet(
            self.network_db, "192.168.0.0/24", do_not_use=True)
        self.ip_address_v4 = netaddr.IPAddress("192.168.0.1")
        self.insert_ip_address(self.ip_address_v4, self.network_db,
                               self.subnet_v4_db)
        self.transaction = self.insert_transaction()
        ip_kwargs = {
            "network_id": self.network_db["id"],
            "reuse_after": self.REUSE_AFTER,
            "deallocated": True,
            "ip_address": None,
            "version": 4,
            "subnet_id": None
        }
        reallocated = db_api.ip_address_reallocate(
            self.context,
            {"transaction_id": self.transaction.id},
            **ip_kwargs)
        self.assertTrue(reallocated)

        updated_address = db_api.ip_address_reallocate_find(
            self.context, self.transaction.id)
        self.assertIsNone(updated_address)
Beispiel #3
0
 def test_normal_one_of_multiple_potential_ip_addresses(self):
     ip_kwargs = {
         "network_id": self.network_db["id"],
         "reuse_after": self.REUSE_AFTER,
         "deallocated": True,
     }
     reallocated = db_api.ip_address_reallocate(
         self.context,
         {"transaction_id": self.transaction.id},
         **ip_kwargs)
     self.assertTrue(reallocated)
Beispiel #4
0
 def test_normal_v6(self):
     ip_kwargs = {
         "network_id": self.network_db["id"],
         "reuse_after": self.REUSE_AFTER,
         "deallocated": True,
         "version": 6,
     }
     reallocated = db_api.ip_address_reallocate(
         self.context,
         {"transaction_id": self.transaction.id},
         **ip_kwargs)
     self.assertTrue(reallocated)
Beispiel #5
0
 def test_reuse_after_not_time_yet(self):
     ip_kwargs = {
         "network_id": self.network_db["id"],
         "reuse_after": self.REUSE_AFTER * 2,
         "deallocated": True,
         "version": 4,
     }
     reallocated = db_api.ip_address_reallocate(
         self.context,
         {"transaction_id": self.transaction.id},
         **ip_kwargs)
     self.assertFalse(reallocated)
Beispiel #6
0
 def test_ip_address_specified_deallocated_None(self):
     ip_kwargs = {
         "network_id": self.network_db["id"],
         "reuse_after": self.REUSE_AFTER,
         "ip_address": self.ip_address_v4,
         "version": 4,
     }
     reallocated = db_api.ip_address_reallocate(
         self.context,
         {"transaction_id": self.transaction.id},
         **ip_kwargs)
     self.assertTrue(reallocated)
Beispiel #7
0
 def test_subnet_ids_specified(self):
     ip_kwargs = {
         "network_id": self.network_db["id"],
         "reuse_after": self.REUSE_AFTER,
         "deallocated": True,
         "version": 4,
         "subnet_id": [self.subnet_v4_db["id"]]
     }
     reallocated = db_api.ip_address_reallocate(
         self.context,
         {"transaction_id": self.transaction.id},
         **ip_kwargs)
     self.assertTrue(reallocated)
Beispiel #8
0
    def test_normal_v6(self):
        self.default_case()
        ip_kwargs = {
            "network_id": self.network_db["id"],
            "reuse_after": self.REUSE_AFTER,
            "deallocated": True,
            "version": 6,
        }
        reallocated = db_api.ip_address_reallocate(
            self.context,
            {"transaction_id": self.transaction.id},
            **ip_kwargs)
        self.assertTrue(reallocated)

        updated_address = db_api.ip_address_reallocate_find(
            self.context, self.transaction.id)
        self.assertEqual(updated_address["address"],
                         int(self.ip_address_v6.ipv6()))
Beispiel #9
0
    def attempt_to_reallocate_ip(self, context, net_id, port_id, reuse_after,
                                 version=None, ip_address=None,
                                 segment_id=None, subnets=None, **kwargs):
        version = version or [4, 6]
        elevated = context.elevated()

        LOG.info("Attempting to reallocate an IP (step 1 of 3) - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, port_id=port_id,
                                version=version, segment_id=segment_id,
                                subnets=subnets, ip_address=ip_address)))

        if version == 6:
            # Defers to the create case. The reason why is we'd have to look
            # up subnets here to correctly generate the v6. If we split them
            # up into reallocate and create, we'd be looking up the same
            # subnets twice, which is a waste of time.

            # TODO(mdietz): after reviewing this code, this block annoyingly
            #               doesn't trigger in the ANY case, since we end up
            #               using a list of [4, 6]. It works as expected most
            #               of the time, but we can anticipate that isolated
            #               networks will end up using sequential assignment.
            #               Probably want to rework this logic to compensate
            #               at some point. Considering they all come from the
            #               same MAC address pool, nothing bad will happen,
            #               just worth noticing and fixing.
            LOG.info("Identified as v6 case, deferring to IP create path")
            return []

        sub_ids = []
        if subnets:
            sub_ids = subnets
        elif segment_id:
            subnets = db_api.subnet_find(elevated,
                                         network_id=net_id,
                                         segment_id=segment_id)
            sub_ids = [s["id"] for s in subnets]
            if not sub_ids:
                LOG.info("No subnets matching segment_id {0} could be "
                         "found".format(segment_id))
                raise ip_address_failure(net_id)

        ip_kwargs = {
            "network_id": net_id,
            "deallocated": True,
            "version": version,
            "lock_id": None,
        }
        if reuse_after is not None:
            ip_kwargs["reuse_after"] = reuse_after
        if ip_address is not None:
            ip_kwargs["ip_address"] = ip_address
            del ip_kwargs["deallocated"]
        if sub_ids:
            ip_kwargs["subnet_id"] = sub_ids

        ipam_log = kwargs.get('ipam_log', None)

        for retry in xrange(CONF.QUARK.ip_address_retry_max):
            attempt = None
            if ipam_log:
                attempt = ipam_log.make_entry("attempt_to_reallocate_ip")
            LOG.info("Attempt {0} of {1}".format(
                retry + 1, CONF.QUARK.ip_address_retry_max))
            try:
                with context.session.begin():
                    transaction = db_api.transaction_create(context)
                m = models.IPAddress
                update_kwargs = {
                    m.transaction_id: transaction.id,
                    m.address_type: kwargs.get("address_type", ip_types.FIXED),
                    m.deallocated: False,
                    m.deallocated_at: None,
                    m.used_by_tenant_id: context.tenant_id,
                    m.allocated_at: timeutils.utcnow(),
                }
                result = db_api.ip_address_reallocate(
                    elevated, update_kwargs, **ip_kwargs)
                if not result:
                    LOG.info("Couldn't update any reallocatable addresses "
                             "given the criteria")
                    if attempt:
                        attempt.failed()
                    break

                updated_address = db_api.ip_address_reallocate_find(
                    elevated, transaction.id)
                if not updated_address:
                    if attempt:
                        attempt.failed()
                    continue

                LOG.info("Address {0} is reallocated".format(
                    updated_address["address_readable"]))
                return [updated_address]
            except Exception:
                if attempt:
                    attempt.failed()
                LOG.exception("Error in reallocate ip...")
            finally:
                if attempt:
                    attempt.end()
        return []
Beispiel #10
0
    def attempt_to_reallocate_ip(self, context, net_id, port_id, reuse_after,
                                 version=None, ip_address=None,
                                 segment_id=None, subnets=None, **kwargs):
        version = version or [4, 6]
        elevated = context.elevated()

        LOG.info("Attempting to reallocate an IP (step 1 of 3) - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, port_id=port_id,
                                version=version, segment_id=segment_id,
                                subnets=subnets)))

        if version == 6:
            # Defers to the create case. The reason why is we'd have to look
            # up subnets here to correctly generate the v6. If we split them
            # up into reallocate and create, we'd be looking up the same
            # subnets twice, which is a waste of time.

            # TODO(mdietz): after reviewing this code, this block annoyingly
            #               doesn't trigger in the ANY case, since we end up
            #               using a list of [4, 6]. It works as expected most
            #               of the time, but we can anticipate that isolated
            #               networks will end up using sequential assignment.
            #               Probably want to rework this logic to compensate
            #               at some point. Considering they all come from the
            #               same MAC address pool, nothing bad will happen,
            #               just worth noticing and fixing.
            LOG.info("Identified as v6 case, deferring to IP create path")
            return []

        sub_ids = []
        if subnets:
            sub_ids = subnets
        elif segment_id:
            subnets = db_api.subnet_find(elevated,
                                         network_id=net_id,
                                         segment_id=segment_id)
            sub_ids = [s["id"] for s in subnets]
            if not sub_ids:
                LOG.info("No subnets matching segment_id {0} could be "
                         "found".format(segment_id))
                raise exceptions.IpAddressGenerationFailure(
                    net_id=net_id)

        ip_kwargs = {
            "network_id": net_id,
            "reuse_after": reuse_after,
            "deallocated": True,
            "ip_address": ip_address,
            "version": version,
        }
        if ip_address:
            del ip_kwargs["deallocated"]
        if sub_ids:
            ip_kwargs["subnet_id"] = sub_ids

        ipam_log = kwargs.get('ipam_log', None)

        for retry in xrange(CONF.QUARK.ip_address_retry_max):
            attempt = None
            if ipam_log:
                attempt = ipam_log.make_entry("attempt_to_reallocate_ip")
            LOG.info("Attempt {0} of {1}".format(
                retry + 1, CONF.QUARK.ip_address_retry_max))
            try:
                with context.session.begin():
                    transaction = db_api.transaction_create(context)
                m = models.IPAddress
                update_kwargs = {
                    m.transaction_id: transaction.id,
                    m.address_type: kwargs.get("address_type", ip_types.FIXED),
                    m.deallocated: False,
                    m.deallocated_at: None,
                    m.used_by_tenant_id: context.tenant_id,
                    m.allocated_at: timeutils.utcnow(),
                }
                result = db_api.ip_address_reallocate(
                    elevated, update_kwargs, **ip_kwargs)
                if not result:
                    LOG.info("Couldn't update any reallocatable addresses "
                             "given the criteria")
                    if attempt:
                        attempt.failed()
                    break

                updated_address = db_api.ip_address_reallocate_find(
                    elevated, transaction.id)
                if not updated_address:
                    if attempt:
                        attempt.failed()
                    continue

                LOG.info("Address {0} is reallocated".format(
                    updated_address["address_readable"]))
                return [updated_address]
            except Exception:
                if attempt:
                    attempt.failed()
                LOG.exception("Error in reallocate ip...")
            finally:
                if attempt:
                    attempt.end()
        return []