Esempio n. 1
0
    def _plug_amphora_vip(self, amphora, subnet):
        # We need a vip port owned by Octavia for Act/Stby and failover
        try:
            port = {
                'port': {
                    'name': 'octavia-lb-vrrp-' + amphora.id,
                    'network_id': subnet.network_id,
                    'fixed_ips': [{
                        'subnet_id': subnet.id
                    }],
                    'admin_state_up': True,
                    'device_owner': OCTAVIA_OWNER
                }
            }
            new_port = self.neutron_client.create_port(port)
            new_port = utils.convert_port_dict_to_model(new_port)

            LOG.debug('Created vip port: %(port_id)s for amphora: %(amp)s', {
                'port_id': new_port.id,
                'amp': amphora.id
            })

            interface = self.plug_port(amphora, new_port)
        except Exception:
            message = _('Error plugging amphora (compute_id: {compute_id}) '
                        'into vip network {network_id}.').format(
                            compute_id=amphora.compute_id,
                            network_id=subnet.network_id)
            LOG.exception(message)
            raise base.PlugVIPException(message)
        return interface
    def allocate_vip(self, load_balancer):
        if not load_balancer.vip.port_id and not load_balancer.vip.subnet_id:
            raise base.AllocateVIPException('Cannot allocate a vip '
                                            'without a port_id or '
                                            'a subnet_id.')
        if load_balancer.vip.port_id:
            LOG.info(_LI('Port %s already exists. Nothing to be done.'),
                     load_balancer.vip.port_id)
            port = self.get_port(load_balancer.vip.port_id)
            return self._port_to_vip(port, load_balancer)

        # Must retrieve the network_id from the subnet
        subnet = self.get_subnet(load_balancer.vip.subnet_id)

        # It can be assumed that network_id exists
        port = {'port': {'name': 'octavia-lb-' + load_balancer.id,
                         'network_id': subnet.network_id,
                         'admin_state_up': False,
                         'device_id': 'lb-{0}'.format(load_balancer.id),
                         'device_owner': OCTAVIA_OWNER}}
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception:
            message = _LE('Error creating neutron port on network '
                          '{network_id}.').format(
                network_id=subnet.network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(message)
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer)
 def create_port(self, network_id, subnet_id=None, fixed_ip=None):
     new_port = None
     if not subnet_id:
         subnet_id = self.get_network(network_id).subnets[0]
     try:
         port = {
             'port': {
                 'name': 'octavia-port-' + network_id,
                 'network_id': network_id,
                 'admin_state_up': True,
                 'device_owner': OCTAVIA_OWNER,
                 'fixed_ips': [{
                     'subnet_id': subnet_id
                 }]
             }
         }
         if fixed_ip:
             port['port']['fixed_ips'][0]['ip_address'] = fixed_ip
         new_port = self.neutron_client.create_port(port)
         new_port = utils.convert_port_dict_to_model(new_port)
     except Exception:
         message = "Error creating port in network: {0}".format(network_id)
         LOG.exception(message)
         raise exceptions.PortCreationFailedException(message)
     return new_port
    def allocate_vip(self, load_balancer):
        if load_balancer.vip.port_id:
            LOG.info('Port %s already exists. Nothing to be done.',
                     load_balancer.vip.port_id)
            port = self.get_port(load_balancer.vip.port_id)
            return self._port_to_vip(port, load_balancer)

        # It can be assumed that network_id exists
        port = {
            'port': {
                'name': 'octavia-lb-' + load_balancer.id,
                'network_id': load_balancer.vip.network_id,
                'admin_state_up': False,
                'device_id': 'lb-{0}'.format(load_balancer.id),
                'device_owner': OCTAVIA_OWNER
            }
        }
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception:
            message = _('Error creating neutron port on network '
                        '{network_id}.').format(
                            network_id=load_balancer.vip.network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(message)
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer)
Esempio n. 5
0
 def reserve_subnet_addresses(self, subnet_id, addr_list, amphorae):
     subnet = self.get_subnet(subnet_id)
     try:
         port = {
             'port': {
                 'name': 'octavia-port-' + subnet.network_id,
                 'network_id': subnet.network_id,
                 'admin_state_up': True,
                 'device_owner': a10constants.OCTAVIA_OWNER,
                 'fixed_ips': []
             }
         }
         for addr in addr_list:
             fixed_ip = {'subnet_id': subnet_id, 'ip_address': addr}
             port['port']['fixed_ips'].append(fixed_ip)
         new_port = self.neutron_client.create_port(port)
         new_port = utils.convert_port_dict_to_model(new_port)
         if amphorae is not None:
             for amphora in filter(
                     lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
                     amphorae):
                 interface = self._get_plugged_interface(
                     amphora.compute_id, subnet.network_id,
                     amphora.lb_network_ip)
                 self._add_allowed_address_pair_to_port(
                     interface.port_id, addr_list)
     except Exception as e:
         LOG.exception(str(e))
         raise e
     return new_port
Esempio n. 6
0
    def allocate_vip(self, load_balancer):
        if not load_balancer.vip.port_id and not load_balancer.vip.subnet_id:
            raise base.AllocateVIPException('Cannot allocate a vip '
                                            'without a port_id or '
                                            'a subnet_id.')
        if load_balancer.vip.port_id:
            LOG.info(_LI('Port %s already exists. Nothing to be done.'),
                     load_balancer.vip.port_id)
            port = self.get_port(load_balancer.vip.port_id)
            return self._port_to_vip(port, load_balancer)

        # Must retrieve the network_id from the subnet
        subnet = self.get_subnet(load_balancer.vip.subnet_id)

        # It can be assumed that network_id exists
        port = {
            'port': {
                'name': 'octavia-lb-' + load_balancer.id,
                'network_id': subnet.network_id,
                'admin_state_up': False,
                'device_id': 'lb-{0}'.format(load_balancer.id),
                'device_owner': OCTAVIA_OWNER
            }
        }
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception:
            message = _LE('Error creating neutron port on network '
                          '{network_id}.').format(network_id=subnet.network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(message)
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer)
Esempio n. 7
0
 def test__port_to_vip(self):
     lb = dmh.generate_load_balancer_tree()
     lb.vip.subnet_id = t_constants.MOCK_SUBNET_ID
     port = utils.convert_port_dict_to_model(t_constants.MOCK_NEUTRON_PORT)
     vip = self.driver._port_to_vip(port, lb)
     self.assertIsInstance(vip, data_models.Vip)
     self.assertEqual(t_constants.MOCK_IP_ADDRESS, vip.ip_address)
     self.assertEqual(t_constants.MOCK_SUBNET_ID, vip.subnet_id)
     self.assertEqual(t_constants.MOCK_PORT_ID, vip.port_id)
     self.assertEqual(lb.id, vip.load_balancer_id)
Esempio n. 8
0
 def test__port_to_vip(self):
     lb = dmh.generate_load_balancer_tree()
     lb.vip.subnet_id = n_constants.MOCK_SUBNET_ID
     port = utils.convert_port_dict_to_model(n_constants.MOCK_NEUTRON_PORT)
     vip = self.driver._port_to_vip(port, lb)
     self.assertIsInstance(vip, data_models.Vip)
     self.assertEqual(n_constants.MOCK_IP_ADDRESS, vip.ip_address)
     self.assertEqual(n_constants.MOCK_SUBNET_ID, vip.subnet_id)
     self.assertEqual(n_constants.MOCK_PORT_ID, vip.port_id)
     self.assertEqual(lb.id, vip.load_balancer_id)
Esempio n. 9
0
    def create_port(self,
                    network_id,
                    name=None,
                    fixed_ips=(),
                    secondary_ips=(),
                    security_group_ids=(),
                    admin_state_up=True,
                    qos_policy_id=None):
        """Creates a network port.

        fixed_ips = [{'subnet_id': <id>, ('ip_addrss': <IP>')},]
        ip_address is optional in the fixed_ips dictionary.

        :param network_id: The network the port should be created on.
        :param name: The name to apply to the port.
        :param fixed_ips: A list of fixed IP dicts.
        :param secondary_ips: A list of secondary IPs to add to the port.
        :param security_group_ids: A list of security group IDs for the port.
        :param qos_policy_id: The QoS policy ID to apply to the port.
        :returns port: A port data model object.
        """
        try:
            aap_list = []
            for ip in secondary_ips:
                aap_list.append({constants.IP_ADDRESS: ip})
            port = {
                constants.NETWORK_ID: network_id,
                constants.ADMIN_STATE_UP: admin_state_up,
                constants.DEVICE_OWNER: OCTAVIA_OWNER
            }
            if aap_list:
                port[constants.ALLOWED_ADDRESS_PAIRS] = aap_list
            if fixed_ips:
                port[constants.FIXED_IPS] = fixed_ips
            if name:
                port[constants.NAME] = name
            if qos_policy_id:
                port[constants.QOS_POLICY_ID] = qos_policy_id
            if security_group_ids:
                port[constants.SECURITY_GROUPS] = security_group_ids

            new_port = self.neutron_client.create_port({constants.PORT: port})

            LOG.debug('Created port: %(port)s', {constants.PORT: new_port})

            return utils.convert_port_dict_to_model(new_port)
        except Exception as e:
            message = _('Error creating a port on network '
                        '{network_id} due to {error}.').format(
                            network_id=network_id, error=str(e))
            LOG.exception(message)
            raise base.CreatePortException(message)
Esempio n. 10
0
    def allocate_vrid_fip(self, vrid, network_id, amphorae, fixed_ip=None):

        fixed_ip_json = {}
        if vrid.subnet_id:
            fixed_ip_json['subnet_id'] = vrid.subnet_id
        if fixed_ip:
            fixed_ip_json['ip_address'] = fixed_ip

        # Make sure we are backward compatible with older neutron
        if self._check_extension_enabled(aap.PROJECT_ID_ALIAS):
            project_id_key = 'project_id'
        else:
            project_id_key = 'tenant_id'

        # It can be assumed that network_id exists
        port = {
            'port': {
                'name': 'octavia-vrid-fip-' + vrid.id,
                'network_id': network_id,
                'admin_state_up': False,
                'device_id': 'vrid-{0}'.format(vrid.id),
                'device_owner': aap.OCTAVIA_OWNER,
                project_id_key: vrid.owner
            }
        }
        if fixed_ip_json:
            port['port']['fixed_ips'] = [fixed_ip_json]

        try:
            new_port = self.neutron_client.create_port(port)
        except Exception as e:
            message = _('Error creating neutron port on network '
                        '{network_id}.').format(network_id=network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(
                message,
                orig_msg=getattr(e, 'message', None),
                orig_code=getattr(e, 'status_code', None),
            )
        new_port = utils.convert_port_dict_to_model(new_port)

        fixed_ip = new_port.fixed_ips[0].ip_address
        for amphora in filter(
                lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
                amphorae):
            interface = self._get_plugged_interface(amphora.compute_id,
                                                    network_id,
                                                    amphora.lb_network_ip)
            self._add_allowed_address_pair_to_port(interface.port_id, fixed_ip)

        return new_port
Esempio n. 11
0
    def _plug_amphora_vip(self, amphora, subnet):
        # We need a vip port owned by Octavia for Act/Stby and failover
        try:
            port = {
                constants.PORT: {
                    constants.NAME: 'octavia-lb-vrrp-' + amphora.id,
                    constants.NETWORK_ID: subnet.network_id,
                    constants.FIXED_IPS: [{
                        'subnet_id': subnet.id
                    }],
                    constants.ADMIN_STATE_UP: True,
                    constants.DEVICE_OWNER: OCTAVIA_OWNER
                }
            }
            new_port = self.neutron_client.create_port(port)
            new_port = utils.convert_port_dict_to_model(new_port)

            LOG.debug('Created vip port: %(port_id)s for amphora: %(amp)s', {
                'port_id': new_port.id,
                'amp': amphora.id
            })

        except Exception as e:
            message = _('Error creating the base (VRRP) port for the VIP with '
                        'port details: {}').format(port)
            LOG.exception(message)
            raise base.PlugVIPException(message) from e

        try:
            interface = self.plug_port(amphora, new_port)
        except Exception as e:
            message = _('Error plugging amphora (compute_id: {compute_id}) '
                        'into vip network {network_id}.').format(
                            compute_id=amphora.compute_id,
                            network_id=subnet.network_id)
            LOG.exception(message)
            try:
                if new_port:
                    self.neutron_client.delete_port(new_port.id)
                    LOG.debug(
                        'Deleted base (VRRP) port %s due to plug_port '
                        'failure.', new_port.id)
            except Exception:
                LOG.exception(
                    'Failed to delete base (VRRP) port %s after '
                    'plug_port failed. This resource is being '
                    'abandoned and should be manually deleted when '
                    'neutron is functional.', new_port.id)
            raise base.PlugVIPException(message) from e
        return interface
Esempio n. 12
0
 def get_port(self, port_id):
     try:
         port = self.neutron_client.show_port(port_id)
         return utils.convert_port_dict_to_model(port)
     except neutron_client_exceptions.NotFound:
         message = _LE('Port not found '
                       '(port id: {port_id}.').format(port_id=port_id)
         LOG.exception(message)
         raise base.PortNotFound(message)
     except Exception:
         message = _LE('Error retrieving port '
                       '(port id: {port_id}.').format(port_id=port_id)
         LOG.exception(message)
         raise base.NetworkException(message)
Esempio n. 13
0
 def get_port(self, port_id):
     try:
         port = self.neutron_client.show_port(port_id)
         return utils.convert_port_dict_to_model(port)
     except neutron_client_exceptions.NotFound:
         message = _LE('Port not found '
                       '(port id: {port_id}.').format(
             port_id=port_id)
         LOG.exception(message)
         raise base.PortNotFound(message)
     except Exception:
         message = _LE('Error retrieving port '
                       '(port id: {port_id}.').format(
             port_id=port_id)
         LOG.exception(message)
         raise base.NetworkException(message)
    def allocate_vip(self, load_balancer):
        if load_balancer.vip.port_id:
            LOG.info('Port %s already exists. Nothing to be done.',
                     load_balancer.vip.port_id)
            port = self.get_port(load_balancer.vip.port_id)
            return self._port_to_vip(port, load_balancer)

        fixed_ip = {}
        if load_balancer.vip.subnet_id:
            fixed_ip['subnet_id'] = load_balancer.vip.subnet_id
        if load_balancer.vip.ip_address:
            fixed_ip['ip_address'] = load_balancer.vip.ip_address

        # Make sure we are backward compatible with older neutron
        if self._check_extension_enabled(PROJECT_ID_ALIAS):
            project_id_key = 'project_id'
        else:
            project_id_key = 'tenant_id'

        # It can be assumed that network_id exists
        port = {
            'port': {
                'name': 'octavia-lb-' + load_balancer.id,
                'network_id': load_balancer.vip.network_id,
                'admin_state_up': False,
                'device_id': 'lb-{0}'.format(load_balancer.id),
                'device_owner': OCTAVIA_OWNER,
                project_id_key: load_balancer.project_id
            }
        }

        if fixed_ip:
            port['port']['fixed_ips'] = [fixed_ip]
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception as e:
            message = _('Error creating neutron port on network '
                        '{network_id}.').format(
                            network_id=load_balancer.vip.network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(
                message,
                orig_msg=getattr(e, 'message', None),
                orig_code=getattr(e, 'status_code', None),
            )
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer)
Esempio n. 15
0
 def test_convert_port_dict_to_model(self):
     model_obj = utils.convert_port_dict_to_model(
         t_constants.MOCK_NEUTRON_PORT)
     assert_dict = dict(
         id=t_constants.MOCK_PORT_ID,
         name=t_constants.MOCK_PORT_NAME,
         device_id=t_constants.MOCK_DEVICE_ID,
         device_owner=t_constants.MOCK_DEVICE_OWNER,
         mac_address=t_constants.MOCK_MAC_ADDR,
         network_id=t_constants.MOCK_NETWORK_ID,
         status=t_constants.MOCK_STATUS,
         project_id=t_constants.MOCK_PROJECT_ID,
         admin_state_up=t_constants.MOCK_ADMIN_STATE_UP,
     )
     self._compare_ignore_value_none(model_obj.to_dict(), assert_dict)
     fixed_ips = t_constants.MOCK_NEUTRON_PORT['port']['fixed_ips']
     for ip in model_obj.fixed_ips:
         self._in_ignore_value_none(ip.to_dict(), fixed_ips)
Esempio n. 16
0
 def test_convert_port_dict_to_model(self):
     model_obj = utils.convert_port_dict_to_model(
         t_constants.MOCK_NEUTRON_PORT)
     assert_dict = dict(
         id=t_constants.MOCK_PORT_ID,
         name=t_constants.MOCK_PORT_NAME,
         device_id=t_constants.MOCK_DEVICE_ID,
         device_owner=t_constants.MOCK_DEVICE_OWNER,
         mac_address=t_constants.MOCK_MAC_ADDR,
         network_id=t_constants.MOCK_NETWORK_ID,
         status=t_constants.MOCK_STATUS,
         project_id=t_constants.MOCK_PROJECT_ID,
         admin_state_up=t_constants.MOCK_ADMIN_STATE_UP,
     )
     self._compare_ignore_value_none(model_obj.to_dict(), assert_dict)
     fixed_ips = t_constants.MOCK_NEUTRON_PORT['port']['fixed_ips']
     for ip in model_obj.fixed_ips:
         self._in_ignore_value_none(ip.to_dict(), fixed_ips)
Esempio n. 17
0
    def allocate_vip(self, load_balancer):
        if load_balancer.vip.port_id:
            LOG.info('Port %s already exists. Nothing to be done.',
                     load_balancer.vip.port_id)
            port = self.get_port(load_balancer.vip.port_id)
            return self._port_to_vip(port, load_balancer)

        fixed_ip = {}
        if load_balancer.vip.subnet_id:
            fixed_ip['subnet_id'] = load_balancer.vip.subnet_id
        if load_balancer.vip.ip_address:
            fixed_ip['ip_address'] = load_balancer.vip.ip_address

        # Make sure we are backward compatible with older neutron
        if self._check_extension_enabled(PROJECT_ID_ALIAS):
            project_id_key = 'project_id'
        else:
            project_id_key = 'tenant_id'

        # It can be assumed that network_id exists
        port = {'port': {'name': 'octavia-lb-' + load_balancer.id,
                         'network_id': load_balancer.vip.network_id,
                         'admin_state_up': False,
                         'device_id': 'lb-{0}'.format(load_balancer.id),
                         'device_owner': OCTAVIA_OWNER,
                         project_id_key: load_balancer.project_id}}

        if fixed_ip:
            port['port']['fixed_ips'] = [fixed_ip]
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception as e:
            message = _('Error creating neutron port on network '
                        '{network_id}.').format(
                network_id=load_balancer.vip.network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(
                message,
                orig_msg=getattr(e, 'message', None),
                orig_code=getattr(e, 'status_code', None),
            )
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer)
Esempio n. 18
0
 def reserve_subnet_addresses(self, subnet_id, addr_list):
     subnet = self.get_subnet(subnet_id)
     try:
         port = {
             'port': {
                 'name': 'octavia-port-' + subnet.network_id,
                 'network_id': subnet.network_id,
                 'admin_state_up': True,
                 'device_owner': OCTAVIA_OWNER,
                 'fixed_ips': []
             }
         }
         for addr in addr_list:
             fixed_ip = {'subnet_id': subnet_id, 'ip_address': addr}
             port['port']['fixed_ips'].append(fixed_ip)
         new_port = self.neutron_client.create_port(port)
         new_port = utils.convert_port_dict_to_model(new_port)
     except Exception as e:
         LOG.exception(str(e))
         raise e
     return new_port
Esempio n. 19
0
    def _plug_amphora_vip(self, amphora, network_id):
        # We need a vip port owned by Octavia for Act/Stby and failover
        try:
            port = {'port': {'name': 'octavia-lb-vrrp-' + amphora.id,
                             'network_id': network_id,
                             'admin_state_up': True,
                             'device_owner': OCTAVIA_OWNER}}
            new_port = self.neutron_client.create_port(port)
            new_port = utils.convert_port_dict_to_model(new_port)

            LOG.debug('Created vip port: {port_id} for amphora: {amp}'.format(
                port_id=new_port.id, amp=amphora.id))

            interface = self.plug_port(amphora, new_port)
        except Exception:
            message = _LE('Error plugging amphora (compute_id: {compute_id}) '
                          'into vip network {network_id}.').format(
                              compute_id=amphora.compute_id,
                              network_id=network_id)
            LOG.exception(message)
            raise base.PlugVIPException(message)
        return interface
    def allocate_vip(self, load_balancer):
        port_id = load_balancer.vip.port_id
        if port_id:
            LOG.info('Port %s already exists. Nothing to be done.', port_id)
            port = self.get_port(port_id)
            return self._port_to_vip(port, load_balancer)

        fixed_ip = {}
        if load_balancer.vip.subnet_id:
            fixed_ip['subnet_id'] = load_balancer.vip.subnet_id
        if load_balancer.vip.ip_address:
            fixed_ip['ip_address'] = load_balancer.vip.ip_address

        # Make sure we are backward compatible with older neutron
        if self._check_extension_enabled(PROJECT_ID_ALIAS):
            project_id_key = 'project_id'
        else:
            project_id_key = 'tenant_id'

        # select a candidate to schedule to
        try:
            session = db_apis.get_session()
            candidate = self.amp_repo.get_candidates(session)[0]
        except ValueError as e:
            message = _('Scheduling failed, no ready candidates found')
            LOG.exception(message)
            raise base.AllocateVIPException(
                message,
                orig_msg=getattr(e, 'message', None),
                orig_code=getattr(e, 'status_code', None),
            )
        LOG.debug("Found candidates for new LB %s: %s", load_balancer.id,
                  candidate)

        # It can be assumed that network_id exists
        port = {
            'port': {
                'name': 'loadbalancer-{}'.format(load_balancer.id),
                'network_id': load_balancer.vip.network_id,
                'admin_state_up': True,
                'device_id': load_balancer.id,
                'device_owner': constants.DEVICE_OWNER_LISTENER,
                'binding:host_id': candidate,
                project_id_key: load_balancer.project_id
            }
        }

        if fixed_ip:
            port['port']['fixed_ips'] = [fixed_ip]
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception as e:
            message = _('Error creating neutron port on network '
                        '{network_id}.').format(
                            network_id=load_balancer.vip.network_id)
            LOG.exception(message)
            raise base.AllocateVIPException(
                message,
                orig_msg=getattr(e, 'message', None),
                orig_code=getattr(e, 'status_code', None),
            )
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer)
Esempio n. 21
0
    def allocate_vip(self, load_balancer):
        if load_balancer.vip.port_id:
            try:
                port = self.get_port(load_balancer.vip.port_id)
                fixed_ip_found = self._validate_fixed_ip(
                    port.fixed_ips, load_balancer.vip.subnet_id,
                    load_balancer.vip.ip_address)
                if (port.network_id == load_balancer.vip.network_id
                        and fixed_ip_found):
                    LOG.info('Port %s already exists. Nothing to be done.',
                             load_balancer.vip.port_id)
                    return self._port_to_vip(port, load_balancer)
                LOG.error(
                    'Neutron VIP mis-match. Expected ip %s on '
                    'subnet %s in network %s. Neutron has fixed_ips %s '
                    'in network %s. Deleting and recreating the VIP '
                    'port.', load_balancer.vip.ip_address,
                    load_balancer.vip.subnet_id, load_balancer.vip.network_id,
                    self._fixed_ips_to_list_of_dicts(port.fixed_ips),
                    port.network_id)
                if load_balancer.vip.octavia_owned:
                    self.delete_port(load_balancer.vip.port_id)
                else:
                    raise base.AllocateVIPException(
                        'VIP port {0} is broken, but is owned by project {1} '
                        'so will not be recreated. Aborting VIP allocation.'.
                        format(port.id, port.project_id))
            except base.AllocateVIPException as e:
                # Catch this explicitly because otherwise we blame Neutron
                LOG.error(getattr(e, constants.MESSAGE, None))
                raise
            except base.PortNotFound:
                LOG.warning('VIP port %s is missing from neutron. Rebuilding.',
                            load_balancer.vip.port_id)
            except Exception as e:
                message = _('Neutron is failing to service requests due to: '
                            '{}. Aborting.').format(str(e))
                LOG.error(message)
                raise base.AllocateVIPException(
                    message,
                    orig_msg=getattr(e, constants.MESSAGE, None),
                    orig_code=getattr(e, constants.STATUS_CODE, None),
                )

        fixed_ip = {}
        if load_balancer.vip.subnet_id:
            fixed_ip['subnet_id'] = load_balancer.vip.subnet_id
        if load_balancer.vip.ip_address:
            fixed_ip[constants.IP_ADDRESS] = load_balancer.vip.ip_address

        # Make sure we are backward compatible with older neutron
        if self._check_extension_enabled(PROJECT_ID_ALIAS):
            project_id_key = 'project_id'
        else:
            project_id_key = 'tenant_id'

        # It can be assumed that network_id exists
        port = {
            constants.PORT: {
                constants.NAME: 'octavia-lb-' + load_balancer.id,
                constants.NETWORK_ID: load_balancer.vip.network_id,
                constants.ADMIN_STATE_UP: False,
                'device_id': 'lb-{0}'.format(load_balancer.id),
                constants.DEVICE_OWNER: OCTAVIA_OWNER,
                project_id_key: load_balancer.project_id
            }
        }

        if fixed_ip:
            port[constants.PORT][constants.FIXED_IPS] = [fixed_ip]
        try:
            new_port = self.neutron_client.create_port(port)
        except Exception as e:
            message = _('Error creating neutron port on network '
                        '{network_id} due to {e}.').format(
                            network_id=load_balancer.vip.network_id, e=str(e))
            LOG.exception(message)
            raise base.AllocateVIPException(
                message,
                orig_msg=getattr(e, constants.MESSAGE, None),
                orig_code=getattr(e, constants.STATUS_CODE, None),
            )
        new_port = utils.convert_port_dict_to_model(new_port)
        return self._port_to_vip(new_port, load_balancer, octavia_owned=True)