Exemple #1
0
    def deallocate(self, address):
        """Deallocate previously allocated address.

        :param address: The address to deallocate.
        :type address: A subclass of netaddr.IPAddress or convertible to one.
        :returns: None
        """
        if not self._ib_network:
            return

        ip_addr = str(address)
        address_request = self._build_address_request_from_ib_address(ip_addr)
        if not address_request:
            return

        ipam_controller = ipam.IpamSyncController(self._ib_cxt)
        dns_controller = dns.DnsController(self._ib_cxt)

        ipam_controller.deallocate_ip(ip_addr)
        port_name = (address_request.port_name
                     if hasattr(address_request, 'port_name')
                     else None)
        dns_controller.unbind_names(ip_addr,
                                    None,
                                    address_request.port_id,
                                    address_request.tenant_id,
                                    address_request.device_id,
                                    address_request.device_owner,
                                    port_name)
    def test_allocate_ip_from_pool(self):
        test_opts = dict()
        self.helper.prepare_test(test_opts)

        subnet_id = 'subnet-id'
        allocation_pools = [{
            'start': '11.11.1.1',
            'end': '11.11.1.150'
        }, {
            'start': '11.11.1.151',
            'end': '11.11.1.253'
        }]
        mac = ':'.join(['00'] * 6)
        dns_view = self.ib_cxt.mapping.dns_view
        zone_auth = 'ib.com'
        hostname = mock.ANY
        ea_ip_address = mock.ANY

        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ipam_controller.pattern_builder = mock.Mock()
        ipam_controller.pattern_builder.get_zone_name.return_value = zone_auth

        ipam_controller.allocate_ip_from_pool(subnet_id, allocation_pools, mac)

        ipam_controller.pattern_builder.get_zone_name.assert_called_once_with(
            is_external=self.ib_cxt.network_is_external)

        self.ib_cxt.ip_alloc.allocate_ip_from_range.assert_called_once_with(
            self.helper.options['network_view'], dns_view, zone_auth, hostname,
            mac, allocation_pools[0]['start'], allocation_pools[0]['end'],
            ea_ip_address)
Exemple #3
0
    def update_subnet(self, rollback_list, subnet_request):
        """Update IPAM Subnet.

        Updates allocation pools, dns zones, or EAs for the subnet in the
        Infoblox backend.
        """
        neutron_subnet = self._build_subnet_from_request(subnet_request)
        ib_network = self._get_ib_network(neutron_subnet['id'],
                                          neutron_subnet['ip_version'])
        if not ib_network:
            raise exc.InfobloxCannotFindSubnet(subnet_id=neutron_subnet['id'],
                                               cidr=neutron_subnet['cidr'])

        ib_cxt = ib_context.InfobloxContext(self._context,
                                            self._context.user_id,
                                            None,
                                            neutron_subnet,
                                            self._grid_config,
                                            plugin=self._plugin,
                                            ib_network=ib_network)

        ipam_controller = ipam.IpamSyncController(ib_cxt)
        dns_controller = dns.DnsController(ib_cxt)

        ipam_controller.update_subnet_allocation_pools(rollback_list)

        if self._is_new_zone_required(neutron_subnet, ib_network):
            # subnet name is used in the domain suffix pattern and the name
            # has been changed; we need to create new zones.
            dns_controller.create_dns_zones(rollback_list)

        ipam_controller.update_subnet_details(ib_network)
    def _test_create_subnet_existing_external_network(self, tenant_mock):
        test_opts = {
            'network_name': 'extnet',
            'subnet_name': 'extsub',
            'cidr': '172.192.1.0/24',
            'external': True,
            'network_exists': True
        }
        self.helper.prepare_test(test_opts)

        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ipam_controller._allocate_pools = mock.Mock()
        tenant = mock.Mock()
        tenant_mock.search = mock.Mock(return_value=tenant)
        with mock.patch.object(ib_objects.Network,
                               'search',
                               return_value=mock.Mock()):
            rollback_list = []
            ipam_controller.create_subnet(rollback_list)

        tenant_mock.search.assert_called_once_with(self.ib_cxt.connector,
                                                   id=self.ib_cxt.tenant_id)
        tenant.update.assert_called_once_with()
        assert tenant.name == self.ib_cxt.tenant_name

        self.ib_cxt.ibom.update_network_options.assert_called_once_with(
            mock.ANY, mock.ANY)
    def allocate(self, address_request):
        """Allocate an IP address based on the request passed in.

        :param address_request: Specifies what to allocate.
        :type address_request: A subclass of AddressRequest
        :returns: A netaddr.IPAddress
        """
        # Validate if network is available for which port
        # association request came.
        # This handle case where subnet is in process of deletion and
        # port allocation comes for update_port.
        if not self._ib_network:
            raise Exception("IB Network: %s not Found in the NIOS" %
                            (self._neutron_subnet['cidr']))

        if not self._validate_network_availability():
            raise Exception(
                "IB Network: %s not Found under Network View: %s" %
                (self._neutron_subnet['cidr'], self._ib_network.network_view))

        ipam_controller = ipam.IpamSyncController(self._ib_cxt)
        dns_controller = dns.DnsController(self._ib_cxt)

        if isinstance(address_request, ipam_req.SpecificAddressRequest):
            allocated_ip = ipam_controller.allocate_specific_ip(
                str(address_request.address), address_request.mac,
                address_request.port_id, address_request.tenant_id,
                address_request.device_id, address_request.device_owner)
        else:
            allocated_ip = ipam_controller.allocate_ip_from_pool(
                self._neutron_subnet.get('id'),
                self._neutron_subnet.get('allocation_pools'),
                address_request.mac, address_request.port_id,
                address_request.tenant_id, address_request.device_id,
                address_request.device_owner)

        port_name = (address_request.port_name if hasattr(
            address_request, 'port_name') else None)
        if allocated_ip and address_request.device_owner:
            # we can deal with instance name as hostname in the ipam agent.
            instance_name = None
            try:
                dns_controller.bind_names(allocated_ip,
                                          instance_name,
                                          address_request.port_id,
                                          address_request.tenant_id,
                                          address_request.device_id,
                                          address_request.device_owner,
                                          port_name=port_name)
            except Exception:
                with excutils.save_and_reraise_exception():
                    ipam_controller.deallocate_ip(allocated_ip,
                                                  address_request.device_owner)

        return allocated_ip
 def create_restart_data(self, allow_service_restart=True):
     helper = IpamControllerTestHelper()
     ib_cxt = helper.ib_cxt
     ib_cxt.grid_config.allow_service_restart = allow_service_restart
     ib_cxt.grid_config.dhcp_support = True
     ib_cxt.ibom.restart_all_services = mock.Mock()
     ipam_controller = ipam.IpamSyncController(ib_cxt)
     member = {'name': 'member1'}
     mock.patch.object(ipam_controller,
                       '_get_service_members',
                       return_value=[member['name']]).start()
     return ib_cxt, ipam_controller, member
    def test_deallocate_ip(self):
        test_opts = dict()
        self.helper.prepare_test(test_opts)

        ip_address = '11.11.1.1'
        dns_view = self.ib_cxt.mapping.dns_view

        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ipam_controller.deallocate_ip(ip_address)

        self.ib_cxt.ip_alloc.deallocate_ip.assert_called_once_with(
            self.helper.options['network_view'], dns_view, ip_address)
Exemple #8
0
    def allocate_subnet(self, rollback_list, subnet_request):
        """Create an IPAM subnet from the subnet request which contains cidr.

        Allocates a subnet to the Infoblox backend.
        :param subnet_request: instance of SubnetRequest child
        :returns: a InfobloxSubnet instance
        """
        # if subnetpool is defined, the request is AnySubnetRequest, so
        # we need to convert it to SpecificSubnetRequest calling
        # SubnetAllocator; however, calling this will not pass custom
        # parameters we defined so we need to get them back from the original
        # subnet_request.
        if self._subnetpool:
            orig_request = {
                'name': subnet_request.name,
                'network_id': subnet_request.network_id,
                'subnetpool_id': subnet_request.subnetpool_id,
                'enable_dhcp': subnet_request.enable_dhcp,
                'dns_nameservers': subnet_request.dns_nameservers
            }
            subnet = super(InfobloxPool, self).allocate_subnet(subnet_request)
            subnet_request = subnet.get_details()
            subnet_request.name = orig_request['name']
            subnet_request.network_id = orig_request['network_id']
            subnet_request.subnetpool_id = orig_request['subnetpool_id']
            subnet_request.enable_dhcp = orig_request['enable_dhcp']
            subnet_request.dns_nameservers = orig_request['dns_nameservers']

        # SubnetRequest must be SpecificSubnet at this point
        if not isinstance(subnet_request, ipam_req.SpecificSubnetRequest):
            raise ipam_exc.InvalidSubnetRequestType(
                subnet_type=type(subnet_request))

        neutron_subnet = self._build_subnet_from_request(subnet_request)
        ib_cxt = ib_context.InfobloxContext(self._context,
                                            self._context.user_id,
                                            None,
                                            neutron_subnet,
                                            self._grid_config,
                                            plugin=self._plugin)

        ipam_controller = ipam.IpamSyncController(ib_cxt)
        dns_controller = dns.DnsController(ib_cxt)

        ib_network = self._create_ib_network(rollback_list, ipam_controller)
        if ib_network:
            dns_controller.create_dns_zones(rollback_list)
            LOG.info("Created DNS zones.")

        return InfobloxSubnet(subnet_request, neutron_subnet, ib_network,
                              ib_cxt)
    def test_delete_subnet_for_external_network_deletable(self):
        test_opts = {'external': True, 'network_exists': True}
        self.helper.prepare_test(test_opts)
        self.grid_config.admin_network_deletion = True

        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ipam_controller._release_service_members = mock.Mock()
        with mock.patch.object(ib_objects.Network,
                               'search_all',
                               return_value=[]):
            ipam_controller.delete_subnet()

        self.ib_cxt.ibom.delete_network.assert_called_once_with(
            self.helper.options['network_view'], self.helper.subnet['cidr'])
    def _test_create_subnet_existing_private_network(self):
        test_opts = {
            'network_exists': True,
            'external': False,
            'shared': False
        }
        self.helper.prepare_test(test_opts)

        self.ib_cxt.mapping.shared = False
        self.ib_cxt.network_is_shared_or_external = False
        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        with mock.patch.object(ib_objects.Network,
                               'search',
                               return_value=mock.Mock()):
            self.assertRaises(exc.InfobloxPrivateSubnetAlreadyExist,
                              ipam_controller.create_subnet, [])
    def test_delete_subnet_for_private_network(self):
        test_opts = {
            'network_exists': True,
            'external': False,
            'shared': False
        }
        self.helper.prepare_test(test_opts)

        self.ib_cxt.mapping.shared = False
        self.ib_cxt.network_is_shared_or_external = False
        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ipam_controller._release_service_members = mock.Mock()
        with mock.patch.object(ib_objects.Network,
                               'search_all',
                               return_value=[]):
            ipam_controller.delete_subnet()

        self.ib_cxt.ibom.delete_network.assert_called_once_with(
            self.helper.options['network_view'], self.helper.subnet['cidr'])
    def get_subnet(self, subnet_id):
        """Retrieve an IPAM subnet.

        :param subnet_id: Neutron subnet identifier
        :returns: a InfobloxSubnet instance
        """
        neutron_subnet = self._fetch_subnet(subnet_id)
        subnet_request = self._build_request_from_subnet(neutron_subnet)

        ib_cxt = ib_context.InfobloxContext(self._context,
                                            self._context.user_id,
                                            None,
                                            neutron_subnet,
                                            self._grid_config,
                                            plugin=self._plugin)

        ipam_controller = ipam.IpamSyncController(ib_cxt)
        ib_network = ipam_controller.get_subnet()
        return InfobloxSubnet(subnet_request, neutron_subnet, ib_network,
                              ib_cxt)
Exemple #13
0
    def allocate(self, address_request):
        """Allocate an IP address based on the request passed in.

        :param address_request: Specifies what to allocate.
        :type address_request: A subclass of AddressRequest
        :returns: A netaddr.IPAddress
        """
        ipam_controller = ipam.IpamSyncController(self._ib_cxt)
        dns_controller = dns.DnsController(self._ib_cxt)

        if isinstance(address_request, ipam_req.SpecificAddressRequest):
            allocated_ip = ipam_controller.allocate_specific_ip(
                str(address_request.address), address_request.mac,
                address_request.port_id, address_request.tenant_id,
                address_request.device_id, address_request.device_owner)
        else:
            allocated_ip = ipam_controller.allocate_ip_from_pool(
                self._neutron_subnet.get('id'),
                self._neutron_subnet.get('allocation_pools'),
                address_request.mac, address_request.port_id,
                address_request.tenant_id, address_request.device_id,
                address_request.device_owner)

        port_name = (address_request.port_name if hasattr(
            address_request, 'port_name') else None)
        if allocated_ip and address_request.device_owner:
            # we can deal with instance name as hostname in the ipam agent.
            instance_name = None
            try:
                dns_controller.bind_names(allocated_ip,
                                          instance_name,
                                          address_request.port_id,
                                          address_request.tenant_id,
                                          address_request.device_id,
                                          address_request.device_owner,
                                          port_name=port_name)
            except Exception:
                with excutils.save_and_reraise_exception():
                    ipam_controller.deallocate_ip(allocated_ip)

        return allocated_ip
    def _test_create_subnet_new_network_view(self, ip_range_mock, tenant_mock):
        test_opts = dict()
        self.helper.prepare_test(test_opts)

        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ip_range_mock.search = mock.Mock(return_value=None)
        tenant = mock.Mock()
        tenant_mock.search = mock.Mock(return_value=tenant)
        with mock.patch.object(ib_objects.Network, 'search',
                               return_value=None):
            ipam_controller._register_mapping_member = mock.Mock()
            rollback_list = []
            ipam_controller.create_subnet(rollback_list)

        tenant_mock.search.assert_called_once_with(self.ib_cxt.connector,
                                                   id=self.ib_cxt.tenant_id)
        tenant.update.assert_called_once_with()
        assert tenant.name == self.ib_cxt.tenant_name

        self.validate_network_creation(self.helper.options['network_view'],
                                       self.helper.subnet)
    def test_update_subnet_allocation_pools(self):
        test_opts = {
            'network_exists': True,
            'external': False,
            'shared': False
        }
        self.helper.prepare_test(test_opts)
        self.ib_cxt.mapping.shared = False
        self.ib_cxt.network_is_shared_or_external = False

        new_pools = (netaddr.IPRange('11.11.1.25', '11.11.1.30'),
                     netaddr.IPRange('11.11.1.45', '11.11.1.60'))
        self.ib_cxt.subnet['allocation_pools'] = new_pools
        ip_version = self.ib_cxt.subnet['ip_version']

        connector = mock.Mock()
        ib_pools = (ib_objects.IPRange(connector,
                                       start_addr='11.11.1.3',
                                       end_addr='11.11.1.19'),
                    ib_objects.IPRange(connector,
                                       start_addr='11.11.1.25',
                                       end_addr='11.11.1.30'))

        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        rollback_list = []
        with mock.patch.object(ib_objects.IPRange,
                               'search_all',
                               return_value=ib_pools):
            ipam_controller.update_subnet_allocation_pools(rollback_list)

            # 1st range from ib_pools should be removed
            ib_pools[0].connector.delete_object.assert_called_once_with(None)

            # 2nd pool from new_pools should be added
            self.ib_cxt.ibom.create_ip_range.assert_called_once_with(
                self.helper.options['network_view'],
                netaddr.IPAddress(new_pools[1].first, ip_version).format(),
                netaddr.IPAddress(new_pools[1].last, ip_version).format(),
                self.helper.subnet['cidr'], mock.ANY, mock.ANY)
Exemple #16
0
    def remove_subnet(self, subnet_id):
        """Remove IPAM Subnet.

        Removes a subnet from the Infoblox backend.
        """
        ib_network = self._get_ib_network(subnet_id)
        if not ib_network:
            return

        neutron_subnet = self._build_subnet_from_ib_network(ib_network)
        ib_cxt = ib_context.InfobloxContext(self._context,
                                            self._context.user_id,
                                            None,
                                            neutron_subnet,
                                            self._grid_config,
                                            plugin=self._plugin,
                                            ib_network=ib_network)

        ipam_controller = ipam.IpamSyncController(ib_cxt)
        dns_controller = dns.DnsController(ib_cxt)

        ipam_controller.delete_subnet(ib_network)
        dns_controller.delete_dns_zones(ib_network=ib_network)
    def test_delete_subnet_for_external_network_not_deletable(self):
        test_opts = {'external': True, 'network_exists': True}
        self.helper.prepare_test(test_opts)
        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ipam_controller._release_service_members = mock.Mock()

        ib_network_ea = self._create_ib_network_ea()
        ib_network_mock = mock.Mock(extattrs=ib_network_ea)
        ib_range_ea = self._create_ib_range_ea()
        ib_ranges_mock = [mock.Mock(extattrs=ib_range_ea)]
        expected_ea = self._reset_ib_range_ea()

        with mock.patch.object(ib_objects.Network,
                               'search_all',
                               return_value=[]):
            with mock.patch.object(ib_objects.IPRange,
                                   'search_all',
                                   return_value=ib_ranges_mock):
                ipam_controller.delete_subnet(ib_network_mock)
                assert ib_network_mock.update.called
                assert ib_network_mock.extattrs.to_dict() == expected_ea
                assert ib_ranges_mock[0].update.called
                assert ib_ranges_mock[0].extattrs.to_dict() == expected_ea
    def test_allocate_specific_ip(self):
        test_opts = dict()
        self.helper.prepare_test(test_opts)

        ip_address = '11.11.1.3'
        mac = ':'.join(['00'] * 6)
        dns_view = self.ib_cxt.mapping.dns_view
        zone_auth = 'ib.com'
        hostname = mock.ANY
        ea_ip_address = mock.ANY

        ipam_controller = ipam.IpamSyncController(self.ib_cxt)
        ipam_controller.pattern_builder = mock.Mock()
        ipam_controller.pattern_builder.get_zone_name.return_value = zone_auth

        ipam_controller.allocate_specific_ip(ip_address, mac)

        ipam_controller.pattern_builder.get_zone_name.assert_called_once_with(
            is_external=self.ib_cxt.network_is_external)

        self.ib_cxt.ip_alloc.allocate_given_ip.assert_called_once_with(
            self.helper.options['network_view'], dns_view, zone_auth, hostname,
            mac, ip_address, ea_ip_address)
Exemple #19
0
def sync_neutron_to_infoblox(context, credentials, grid_manager):
    """Sync neutron objects to Infoblox grid

    Prerequisites:
        1. network views to sync must have "Cloud Adapter ID" EA set.
        2. infoblox agent sync should have been processed and updated members
           and network views.
    """
    LOG.info("Starting migration...\n")

    delete_unknown_ips = cfg.CONF.delete_unknown_ips

    grid_config = grid_manager.grid_config
    grid_id = grid_config.grid_id
    session = context.session

    neutron_api = neutron_client.Client(**credentials)
    payload = neutron_api.list_networks()
    networks = payload['networks']
    if not networks:
        LOG.info("No network exists...Exiting...")
        return

    payload = neutron_api.list_subnets()
    subnets = payload['subnets']
    if not subnets:
        LOG.info("No subnet exists...Exiting...")
        return

    payload = neutron_api.list_ports()
    ports = payload['ports']
    nova_api = nova_client.Client(NOVA_API_VERSION,
                                  session=credentials['session'])

    instance_names_by_instance_id = dict()
    instance_names_by_floating_ip = dict()
    for server in nova_api.servers.list(search_opts={'all_tenants': 1}):
        instance_names_by_instance_id[server.id] = server.name
        floating_ips = []
        for net in server.addresses:
            floating_ips += [
                ip['addr'] for ip in server.addresses[net]
                if ip['OS-EXT-IPS:type'] == 'floating'
            ]
        for fip in floating_ips:
            instance_names_by_floating_ip[fip] = server.name

    user_id = neutron_api.httpclient.get_user_id()
    user_tenant_id = neutron_api.httpclient.get_project_id()

    ib_networks = []
    should_exit = False

    # sync subnets
    for subnet in subnets:
        subnet_id = subnet['id']
        subnet_name = subnet['name']
        network_id = subnet['network_id']
        network = utils.find_one_in_list('id', network_id, networks)
        if not network:
            LOG.warning("network (%s) is not found. Skipping subnet (%s)",
                        network_id, subnet_id)
            continue

        network_name = network['name']
        ib_cxt = ib_context.InfobloxContext(context,
                                            user_id,
                                            network,
                                            subnet,
                                            grid_config,
                                            plugin=neutron_api)
        db_mapped_netview = dbi.get_network_view_by_mapping(
            session,
            grid_id=grid_id,
            network_id=network_id,
            subnet_id=subnet_id)
        if db_mapped_netview:
            LOG.info("Mapping found for network (%s), subnet (%s)",
                     network_name, subnet_name)
            if len(db_mapped_netview) > 1:
                LOG.warning("More that one db_mapped_netview returned")
            if delete_unknown_ips:
                ib_network = ib_objects.Network.search(
                    ib_cxt.connector,
                    network_view=db_mapped_netview[0].network_view,
                    cidr=subnet.get('cidr'))
                ib_networks.append(ib_network)
            continue

        ipam_controller = ipam.IpamSyncController(ib_cxt)
        dns_controller = dns.DnsController(ib_cxt)

        rollback_list = []
        try:
            ib_network = ipam_controller.create_subnet(rollback_list)
            if ib_network:
                if delete_unknown_ips:
                    ib_networks.append(ib_network)
                dns_controller.create_dns_zones(rollback_list)
            LOG.info("Created network (%s), subnet (%s)", network_name,
                     subnet_name)
        except Exception as e:
            LOG.error(_LE("Error occurred: %(error)s"), {'error': e})
            for ib_obj in reversed(rollback_list):
                try:
                    ib_obj.delete()
                except ib_exc.InfobloxException as e:
                    LOG.warning(
                        _LW("Unable to delete %(obj)s due to "
                            "error: %(error)s."), {
                                'obj': ib_obj,
                                'error': e
                            })
            should_exit = True
            break

    if should_exit:
        LOG.info("Exiting due to the error in creating subnet...")
        return

    # sync ports
    for port in ports:
        port_id = port['id']
        port_name = port['name']
        port_mac_address = port['mac_address']
        tenant_id = port.get('tenant_id') or user_tenant_id
        network_id = port['network_id']
        device_owner = port['device_owner']
        device_id = port['device_id']

        instance_name = (instance_names_by_instance_id[device_id] if device_id
                         in instance_names_by_instance_id else None)

        network = utils.find_one_in_list('id', network_id, networks)
        if not network:
            LOG.error("network (%s) not found", network_id)
            break

        for ip_set in port.get('fixed_ips'):
            subnet_id = ip_set['subnet_id']
            ip_address = ip_set['ip_address']
            LOG.info("Adding port for %s: %s...", device_owner, ip_address)

            subnet = utils.find_one_in_list('id', subnet_id, subnets)
            if not subnet:
                should_exit = True
                LOG.error("subnet (%s) not found", subnet_id)
                break

            ib_cxt = ib_context.InfobloxContext(context,
                                                user_id,
                                                network,
                                                subnet,
                                                grid_config,
                                                plugin=neutron_api)
            connector = ib_cxt.connector
            netview = ib_cxt.mapping.network_view

            search_fields = {'network_view': netview, 'ip_address': ip_address}
            obj_type = ('ipv4address' if utils.get_ip_version(ip_address) == 4
                        else 'ipv6address')
            ib_address = connector.get_object(obj_type,
                                              search_fields,
                                              return_fields=['objects'],
                                              force_proxy=True)
            if ib_address and ib_address[0]['objects']:
                LOG.info("%s is found...no need to create", ip_address)
                continue

            ipam_controller = ipam.IpamSyncController(ib_cxt)
            dns_controller = dns.DnsController(ib_cxt)

            # for a floating ip port, check for its association.
            # if associated, then port info needs to be the associated port,
            # not the floating ip port because the associated port contains
            # actual attached device info
            is_floating_ip = False
            if ip_address in instance_names_by_floating_ip:
                db_floatingip = dbi.get_floatingip_by_ip_address(
                    session, ip_address)
                db_port = dbi.get_port_by_id(session,
                                             db_floatingip.fixed_port_id)
                port_id = db_port.id
                port_name = db_port.name
                tenant_id = db_port.tenant_id
                device_id = db_port.device_id
                device_owner = db_port.device_owner
                instance_name = instance_names_by_floating_ip[ip_address]
                is_floating_ip = True

            allocated_ip = ipam_controller.allocate_specific_ip(
                ip_address, port_mac_address, port_id, tenant_id, device_id,
                device_owner)
            if allocated_ip and device_owner:
                try:
                    dns_controller.bind_names(allocated_ip, instance_name,
                                              port_id, tenant_id, device_id,
                                              device_owner, is_floating_ip,
                                              port_name)
                except Exception as e:
                    should_exit = True
                    LOG.error("Unable to allocate ip (%s): %s", ip_address, e)
                    ipam_controller.deallocate_ip(allocated_ip)
                    break

            LOG.info("Allocated %s", ip_address)

        if should_exit:
            LOG.info("Existing due to error in port creation...")
            break

    if delete_unknown_ips:
        LOG.info("Start deleting unknown Fixed IP's from Infoblox...")
        for ib_network in ib_networks:

            nw_ea = ib_network.extattrs
            # Skip network if it doesn't have EA or if EA indicates it's
            # shared or external.
            if (not nw_ea or nw_ea.get('Is External')
                    or nw_ea.get('Is Shared')):
                continue

            LOG.info("Searching for Fixed IP: network_view='%s', cidr='%s'" %
                     (ib_network.network_view, ib_network.network))
            fixed_ips = ib_objects.FixedAddress.search_all(
                ib_cxt.connector,
                network_view=ib_network.network_view,
                network=ib_network.network)

            if not fixed_ips:
                LOG.info("No FixedIP found: network_view='%s', cidr='%s'" %
                         (ib_network.network_view, ib_network.network))
                continue

            for fixed_ip in fixed_ips:
                ea = fixed_ip.extattrs
                port_id = None
                if ea:
                    port_id = ea.get('Port ID')

                # Delete Fixed IP if:
                #   - Fixed IP does not have 'Port ID' EA, or
                #   - No port_id in neutron matches 'Port ID' EA value
                if not (port_id
                        and utils.find_one_in_list('id', port_id, ports)):
                    LOG.info("Deleting Fixed IP from Infoblox: '%s'" %
                             fixed_ip)
                    fixed_ip.delete()

    LOG.info("Ending migration...")