Пример #1
0
 def test_delete_port_on_error_port_does_not_exist(self):
     core_plugin, context = mock.Mock(), mock.Mock()
     port_id = 'pid'
     core_plugin.delete_port.side_effect = exceptions.PortNotFound(
         port_id=port_id)
     with testtools.ExpectedException(exceptions.PortNotFound):
         with utils.delete_port_on_error(core_plugin, context, port_id):
             raise exceptions.PortNotFound(port_id=port_id)
     core_plugin.delete_port.assert_called_once_with(context,
                                                     port_id,
                                                     l3_port_check=False)
Пример #2
0
 def get_port(self, context, _id, fields=None):
     try:
         b_port = self.core_plugin.get_port(context, _id, fields)
     except q_exceptions.NotFound:
         t_ctx = t_context.get_context_from_neutron_context(context)
         if self._skip_non_api_query(t_ctx):
             raise q_exceptions.PortNotFound(port_id=_id)
         t_port = self.neutron_handle.handle_get(t_ctx, 'port', _id)
         if not t_port:
             raise q_exceptions.PortNotFound(port_id=_id)
         self._ensure_network_subnet(context, t_port)
         self._adapt_port_body_for_call(t_port)
         self._handle_security_group(t_ctx, context, t_port)
         b_port = self.core_plugin.create_port(context, {'port': t_port})
     return self._fields(b_port, fields)
Пример #3
0
    def update_floatingip(self, context, fpid, floatingip):
        port_id_specified = 'port_id' in floatingip['floatingip']
        if not port_id_specified:
            LOG.error(_LE("port_id key is not found in %s"), floatingip)
            raise exc.PortNotFound(port_id=None)

        port_id = floatingip['floatingip'].get('port_id')
        try:
            if port_id_specified and not port_id:
                floating = context.session.query(l3_db.FloatingIP).filter_by(
                    id=fpid).one()
                self._delete_nat(context, floating)
        except sa.orm.exc.NoResultFound:
            raise exc.PortNotFound(port_id=port_id)

        ret = super(NECNWAL3Plugin, self).update_floatingip(
            context, fpid, floatingip)

        try:
            if port_id_specified and port_id:
                floating = context.session.query(l3_db.FloatingIP).filter_by(
                    id=fpid).one()
                tenant_id = nwa_l3_db.get_tenant_id_by_router(
                    context.session,
                    floating['router_id']
                )
                nwa_tenant_id = nwa_com_utils.get_nwa_tenant_id(tenant_id)

                fl_data = {
                    'floating_ip_address': floating['floating_ip_address'],
                    'fixed_ip_address': floating['fixed_ip_address'],
                    'id': fpid, 'device_id': floating['router_id'],
                    'floating_network_id': floating['floating_network_id'],
                    'tenant_id': floating['tenant_id'],
                    'floating_port_id': floating['floating_port_id']
                }
                LOG.info(_LI('setting_nat fl_data is %s'), fl_data)
                proxy = self._get_nwa_proxy(self, tenant_id)
                proxy.setting_nat(
                    context, tenant_id=tenant_id,
                    nwa_tenant_id=nwa_tenant_id,
                    floating=fl_data
                )

        except sa.orm.exc.NoResultFound:
            raise exc.PortNotFound(port_id=port_id)

        return ret
Пример #4
0
    def create(self):
        with db_api.autonested_transaction(self.obj_context.session):
            try:
                super(SubPort, self).create()
            except o_db_exc.DBReferenceError as ex:
                if ex.key_table is None:
                    # NOTE(ivc): 'key_table' is provided by 'oslo.db' [1]
                    # only for a limited set of database backends (i.e.
                    # MySQL and PostgreSQL). Other database backends
                    # (including SQLite) would have 'key_table' set to None.
                    # We emulate the 'key_table' support for such database
                    # backends.
                    #
                    # [1] https://github.com/openstack/oslo.db/blob/3fadd5a
                    #     /oslo_db/sqlalchemy/exc_filters.py#L190-L203
                    if not Trunk.get_object(self.obj_context,
                                            id=self.trunk_id):
                        ex.key_table = Trunk.db_model.__tablename__

                if ex.key_table == Trunk.db_model.__tablename__:
                    raise t_exc.TrunkNotFound(trunk_id=self.trunk_id)

                raise n_exc.PortNotFound(port_id=self.port_id)
            except base.NeutronDbObjectDuplicateEntry:
                raise t_exc.DuplicateSubPort(
                    segmentation_type=self.segmentation_type,
                    segmentation_id=self.segmentation_id,
                    trunk_id=self.trunk_id)
Пример #5
0
 def test_update_port_missing_port_on_update(self):
     self.plugin.get_port.return_value = {
         'device_id': n_const.DEVICE_ID_RESERVED_DHCP_PORT}
     self.plugin.update_port.side_effect = n_exc.PortNotFound(port_id='66')
     self.assertIsNone(self.callbacks.update_dhcp_port(
         context='ctx', host='host', port_id='66',
         port={'port': {'network_id': 'a'}}))
Пример #6
0
def delete_port(context, id):
    """Delete a port.

    : param context: neutron api request context
    : param id: UUID representing the port to delete.
    """
    LOG.info("delete_port %s for tenant %s" % (id, context.tenant_id))

    port = db_api.port_find(context, id=id, scope=db_api.ONE)
    if not port:
        raise n_exc.PortNotFound(port_id=id)

    if 'device_id' in port:  # false is weird, but ignore that
        LOG.info("delete_port %s for tenant %s has device %s" %
                 (id, context.tenant_id, port['device_id']))

    backend_key = port["backend_key"]
    mac_address = netaddr.EUI(port["mac_address"]).value
    ipam_driver = _get_ipam_driver(port["network"], port=port)
    ipam_driver.deallocate_mac_address(context, mac_address)
    ipam_driver.deallocate_ips_by_port(
        context, port, ipam_reuse_after=CONF.QUARK.ipam_reuse_after)

    net_driver = _get_net_driver(port["network"], port=port)
    base_net_driver = _get_net_driver(port["network"])
    net_driver.delete_port(context,
                           backend_key,
                           device_id=port["device_id"],
                           mac_address=port["mac_address"],
                           base_net_driver=base_net_driver)

    with context.session.begin():
        db_api.port_delete(context, port)
Пример #7
0
 def _get_port(self, context, id, lazy_fields=None):
     try:
         port = model_query.get_by_id(context, models_v2.Port, id,
                                      lazy_fields=lazy_fields)
     except exc.NoResultFound:
         raise exceptions.PortNotFound(port_id=id)
     return port
Пример #8
0
def get_port_for_ip_address(context, ip_id, id, fields=None):
    """Retrieve a port.

    : param context: neutron api request context
    : param id: UUID representing the port to fetch.
    : param fields: a list of strings that are valid keys in a
        port dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
        object in neutron/api/v2/attributes.py. Only these fields
        will be returned.
    """
    LOG.info("get_port %s for tenant %s fields %s" %
             (id, context.tenant_id, fields))
    addr = db_api.ip_address_find(context, id=ip_id, scope=db_api.ONE)
    if not addr:
        raise q_exc.IpAddressNotFound(addr_id=ip_id)

    filters = {'ip_address_id': [ip_id]}
    results = db_api.port_find(context,
                               id=id,
                               fields=fields,
                               scope=db_api.ONE,
                               **filters)

    if not results:
        raise n_exc.PortNotFound(port_id=id)

    return v._make_port_for_ip_dict(addr, results)
Пример #9
0
def _get_port(context, port_id):
    port = db_api.port_find(context, id=port_id, scope=db_api.ONE)
    if not port:
        raise n_exc.PortNotFound(port_id=port_id)

    if not port.ip_addresses or len(port.ip_addresses) == 0:
        raise q_exc.NoAvailableFixedIpsForPort(port_id=port_id)
    return port
Пример #10
0
 def test_update_port_missing_port_on_get(self):
     self.plugin.get_port.side_effect = n_exc.PortNotFound(port_id='66')
     self.assertIsNone(
         self.callbacks.update_dhcp_port(context='ctx',
                                         host='host',
                                         port_id='66',
                                         port={'port': {
                                             'network_id': 'a'
                                         }}))
Пример #11
0
 def test_delete_floatingip_deleted_port_no_notify(self):
     port_id = 'bee50827-bcee-4cc8-91c1-a27b0ce54222'
     with mock.patch.object(directory.get_plugin(), 'get_port',
             side_effect=n_exc.PortNotFound(port_id=port_id)):
         returned_obj = {'floatingip':
                         {'port_id': port_id}}
         event = self.nova_notifier.create_port_changed_event(
             'delete_floatingip', {}, returned_obj)
         self.assertIsNone(event)
Пример #12
0
 def test_convert_exception_to_http_exc_multiple_same_codes(self):
     e = exceptions.MultipleExceptions([
         exceptions.NetworkNotFound(net_id='nid'),
         exceptions.PortNotFound(port_id='pid')
     ])
     conv = common.convert_exception_to_http_exc(e, base_v2.FAULT_MAP, None)
     self.assertIsInstance(conv, exc.HTTPNotFound)
     self.assertEqual(
         "Network nid could not be found.\nPort pid could not be found.",
         jsonutils.loads(conv.body)['NeutronError']['message'])
Пример #13
0
    def test_remove_router_interface(self, getp):
        router_id = 'router-id'
        interface_info = {'port_id': 'router-port-id'}
        getp.side_effect = n_exc.PortNotFound(port_id='router-port-id')

        self.l3_inst.remove_router_interface(self.context, router_id,
                                             interface_info)

        self.l3_inst._ovn.delete_lrouter_port.assert_called_once_with(
            'lrp-router-port-id', 'neutron-router-id', if_exists=True)
Пример #14
0
 def test_update_routers_states_port_not_found(self):
     router1 = self._create_router()
     port = {'id': 'foo', 'device_id': router1['id']}
     with mock.patch.object(self.core_plugin, 'get_ports',
                            return_value=[port]):
         with mock.patch.object(
                 self.core_plugin, 'update_port',
                 side_effect=n_exc.PortNotFound(port_id='foo')):
             states = {router1['id']: 'active'}
             self.plugin.update_routers_states(
                 self.admin_ctx, states, self.agent1['host'])
 def test_delete_resource_port_handle_port_not_found(self):
     mgmt_port_id = 'fake_port_id'
     mocked_plugin = mock.MagicMock()
     mock_ctx = mock.MagicMock()
     mocked_plugin.delete_port = mock.MagicMock(
         side_effect=n_exc.PortNotFound(port_id=mgmt_port_id))
     with mock.patch.object(VIFHotPlugPluggingDriver,
                            '_core_plugin') as plugin:
         plugin.__get__ = mock.MagicMock(return_value=mocked_plugin)
         vif_plugging_driver = VIFHotPlugPluggingDriver()
         vif_plugging_driver._delete_resource_port(mock_ctx, mgmt_port_id)
         self.assertEqual(1, mocked_plugin.delete_port.call_count)
Пример #16
0
 def clean_by_port(self, port):
     """Detach port from policy and cleanup data we don't need anymore."""
     port_id = port['port_id']
     if port_id in self.port_policies:
         del self.port_policies[port_id]
         for qos_policy_id, port_dict in self.qos_policy_ports.items():
             if port_id in port_dict:
                 del port_dict[port_id]
                 if not port_dict:
                     self._clean_policy_info(qos_policy_id)
                 return
     raise exceptions.PortNotFound(port_id=port['port_id'])
Пример #17
0
 def test_convert_exception_to_http_exc_multiple_different_codes(self):
     e = exceptions.MultipleExceptions([
         exceptions.NetworkInUse(net_id='nid'),
         exceptions.PortNotFound(port_id='pid')
     ])
     conv = common.convert_exception_to_http_exc(e, base_v2.FAULT_MAP, None)
     self.assertIsInstance(conv, exc.HTTPConflict)
     self.assertEqual(
         ("HTTP 409 NetworkInUse: Unable to complete operation on network "
          "nid. There are one or more ports still in use on the network.\n"
          "HTTP 404 PortNotFound: Port pid could not be found."),
         jsonutils.loads(conv.body)['NeutronError']['message'])
Пример #18
0
 def test_synchronize_port_not_found_in_db_no_raise(self):
     ctx = context.get_admin_context()
     with self._populate_data(ctx):
         # Put a port down to verify synchronization
         lp_uuid = list(self.fc._fake_lswitch_lport_dict)[0]
         lport = self.fc._fake_lswitch_lport_dict[lp_uuid]
         q_port_id = self._get_tag_dict(lport['tags'])['q_port_id']
         lport['status'] = 'true'
         q_port_data = self._plugin._get_port(ctx, q_port_id)
         with mock.patch.object(self._plugin, '_get_port') as _get_port:
             _get_port.side_effect = n_exc.PortNotFound(
                 port_id=q_port_data['id'])
             self._plugin._synchronizer.synchronize_port(ctx, q_port_data)
Пример #19
0
 def test_update_port_unbound_agent(self):
     self.plugin.get_port.return_value = {
         'device_id': n_const.DEVICE_ID_RESERVED_DHCP_PORT}
     self.plugin.update_port.side_effect = n_exc.PortNotFound(port_id='66')
     self.callbacks.is_agent_bound_to_network = \
         _fake_is_agent_bound_to_network_false
     port = {'port': {'network_id': 'a'}}
     self.assertRaises(exceptions.DhcpPortInUse,
                       self.callbacks.update_dhcp_port,
                       mock.Mock(),
                       host='host',
                       port_id='66',
                       port=port)
Пример #20
0
    def test_remove_router_interface(self, getp):
        router_id = 'router-id'
        interface_info = {'port_id': 'router-port-id'}
        getp.side_effect = n_exc.PortNotFound(port_id='router-port-id')
        with mock.patch(
                'neutron.db.l3_db.L3_NAT_dbonly_mixin.'
                'remove_router_interface',
                return_value=interface_info):
            self.l3_plugin.remove_router_interface(self.context, router_id,
                                                   interface_info)

        self.l3_plugin._ovn.delete_lrouter_port.assert_called_once_with(
            'lrp-router-port-id', 'neutron-router-id', if_exists=False)
Пример #21
0
    def test_remove_router_interface_with_gateway_set(self, gr, gs, gp):
        router_id = 'router-id'
        interface_info = {'port_id': 'router-port-id',
                          'subnet_id': 'subnet-id'}
        gr.return_value = self.fake_router_with_ext_gw
        gs.return_value = self.fake_subnet
        gp.side_effect = n_exc.PortNotFound(port_id='router-port-id')
        self.l3_inst.remove_router_interface(
            self.context, router_id, interface_info)

        self.l3_inst._ovn.delete_lrouter_port.assert_called_once_with(
            'lrp-router-port-id', 'neutron-router-id', if_exists=True)
        self.l3_inst._ovn.delete_nat_rule_in_lrouter.assert_called_once_with(
            'neutron-router-id', logical_ip='10.0.0.0/24',
            external_ip='192.168.1.1', type='snat')
Пример #22
0
def diagnose_port(context, id, fields):
    if not context.is_admin:
        raise n_exc.NotAuthorized()

    if id == "*":
        return {
            'ports': [
                _diag_port(context, port, fields)
                for port in db_api.port_find(context).all()
            ]
        }
    db_port = db_api.port_find(context, id=id, scope=db_api.ONE)
    if not db_port:
        raise n_exc.PortNotFound(port_id=id)
    port = _diag_port(context, db_port, fields)
    return {'ports': port}
Пример #23
0
    def create(self):
        with db_api.autonested_transaction(self.obj_context.session):
            sub_ports = []
            if self.obj_attr_is_set('sub_ports'):
                sub_ports = self.sub_ports

            try:
                super(Trunk, self).create()
            except o_db_exc.DBReferenceError:
                raise n_exc.PortNotFound(port_id=self.port_id)

            if sub_ports:
                for sub_port in sub_ports:
                    sub_port.trunk_id = self.id
                    sub_port.create()
                    self.sub_ports.append(sub_port)
                self.obj_reset_changes(['sub_ports'])
Пример #24
0
    def create(self):
        with self.db_context_writer(self.obj_context):
            sub_ports = []
            if self.obj_attr_is_set('sub_ports'):
                sub_ports = self.sub_ports

            try:
                super(Trunk, self).create()
            except o_db_exc.DBReferenceError:
                raise n_exc.PortNotFound(port_id=self.port_id)

            if sub_ports:
                for sub_port in sub_ports:
                    sub_port.trunk_id = self.id
                    sub_port.create()
                    self.sub_ports.append(sub_port)
                self.obj_reset_changes(['sub_ports'])
Пример #25
0
 def _get_port(self, context, id):
     try:
         port = self._get_by_id(context, models_v2.Port, id)
     except exc.NoResultFound:
         raise n_exc.PortNotFound(port_id=id)
     return port
Пример #26
0
 def test_update_device_up_notify_not_sent_with_port_not_found(self):
     self.plugin._get_port.side_effect = (exceptions.PortNotFound(
         port_id='foo_port_id'))
     notify = self._test_update_device_up()
     self.assertFalse(notify.call_count)
Пример #27
0
def update_ip_address(context, id, ip_address):
    """Due to NCP-1592 ensure that address_type cannot change after update."""
    LOG.info("update_ip_address %s for tenant %s" % (id, context.tenant_id))
    ports = []
    if 'ip_address' not in ip_address:
        raise n_exc.BadRequest(resource="ip_addresses",
                               msg="Invalid request body.")
    with context.session.begin():
        address = db_api.ip_address_find(context, id=id, scope=db_api.ONE)
        if not address:
            raise q_exc.IpAddressNotFound(addr_id=id)
        iptype = address.address_type
        if iptype == ip_types.FIXED and not CONF.QUARK.ipaddr_allow_fixed_ip:
            raise n_exc.BadRequest(
                resource="ip_addresses",
                msg="Fixed ips cannot be updated using this interface.")

        reset = ip_address['ip_address'].get('reset_allocation_time', False)
        if reset and address['deallocated'] == 1:
            if context.is_admin:
                LOG.info("IP's deallocated time being manually reset")
                address['deallocated_at'] = _get_deallocated_override()
            else:
                msg = "Modification of reset_allocation_time requires admin"
                raise webob.exc.HTTPForbidden(detail=msg)

        port_ids = ip_address['ip_address'].get('port_ids', None)

        if port_ids is not None and not port_ids:
            raise n_exc.BadRequest(
                resource="ip_addresses",
                msg="Cannot be updated with empty port_id list")

        if iptype == ip_types.SHARED:
            has_owner = address.has_any_shared_owner()

        if port_ids:
            if iptype == ip_types.FIXED and len(port_ids) > 1:
                raise n_exc.BadRequest(
                    resource="ip_addresses",
                    msg="Fixed ips cannot be updated with more than one port.")

            _raise_if_shared_and_enabled(ip_address, address)
            ports = db_api.port_find(context,
                                     tenant_id=context.tenant_id,
                                     id=port_ids,
                                     scope=db_api.ALL)
            # NOTE(name): could be considered inefficient because we're
            # converting to a list to check length. Maybe revisit
            if len(ports) != len(port_ids):
                raise n_exc.PortNotFound(port_id=port_ids)

            validate_and_fetch_segment(ports, address["network_id"])
            validate_port_ip_quotas(context, address.network_id, ports)

            if iptype == ip_types.SHARED and has_owner:
                for assoc in address.associations:
                    pid = assoc.port_id
                    if pid not in port_ids and 'none' != assoc.service:
                        raise q_exc.PortRequiresDisassociation()

            LOG.info("Updating IP address, %s, to only be used by the"
                     "following ports:  %s" %
                     (address.address_readable, [p.id for p in ports]))
            new_address = db_api.update_port_associations_for_ip(
                context, ports, address)
        elif iptype == ip_types.SHARED and has_owner:
            raise q_exc.PortRequiresDisassociation()
        else:
            ipam_driver.deallocate_ip_address(context, address)
            return v._make_ip_dict(address)
    return v._make_ip_dict(new_address)
Пример #28
0
def _update_flip(context, flip_id, ip_type, requested_ports):
    """Update a flip based IPAddress

    :param context: neutron api request context.
    :param flip_id: id of the flip or scip
    :param ip_type: ip_types.FLOATING | ip_types.SCALING
    :param requested_ports: dictionary of the structure:
    {"port_id": "<id of port>", "fixed_ip": "<fixed ip address>"}
    :return: quark.models.IPAddress
    """
    # This list will hold flips that require notifications.
    # Using sets to avoid dups, if any.
    notifications = {billing.IP_ASSOC: set(), billing.IP_DISASSOC: set()}

    context.session.begin()
    try:
        flip = db_api.floating_ip_find(context, id=flip_id, scope=db_api.ONE)
        if not flip:
            if ip_type == ip_types.SCALING:
                raise q_exc.ScalingIpNotFound(id=flip_id)
            raise q_exc.FloatingIpNotFound(id=flip_id)
        current_ports = flip.ports

        # Determine what ports are being removed, being added, and remain
        req_port_ids = [
            request_port.get('port_id') for request_port in requested_ports
        ]
        curr_port_ids = [curr_port.id for curr_port in current_ports]
        added_port_ids = [
            port_id for port_id in req_port_ids
            if port_id and port_id not in curr_port_ids
        ]
        removed_port_ids = [
            port_id for port_id in curr_port_ids if port_id not in req_port_ids
        ]
        remaining_port_ids = set(curr_port_ids) - set(removed_port_ids)

        # Validations just for floating ip types
        if (ip_type == ip_types.FLOATING and curr_port_ids
                and curr_port_ids == req_port_ids):
            d = dict(flip_id=flip_id, port_id=curr_port_ids[0])
            raise q_exc.PortAlreadyAssociatedToFloatingIp(**d)
        if (ip_type == ip_types.FLOATING and not curr_port_ids
                and not req_port_ids):
            raise q_exc.FloatingIpUpdateNoPortIdSupplied()

        # Validate that GW IP is not in use on the NW.
        flip_subnet = v._make_subnet_dict(flip.subnet)
        for added_port_id in added_port_ids:
            port = _get_port(context, added_port_id)
            nw = port.network
            nw_ports = v._make_ports_list(nw.ports)
            fixed_ips = [
                ip.get('ip_address') for p in nw_ports
                for ip in p.get('fixed_ips')
            ]

            gw_ip = flip_subnet.get('gateway_ip')
            if gw_ip in fixed_ips:
                port_with_gateway_ip = None
                for port in nw_ports:
                    for ip in port.get('fixed_ips'):
                        if gw_ip in ip.get('ip_address'):
                            port_with_gateway_ip = port
                            break
                port_id = port_with_gateway_ip.get('id')
                network_id = port_with_gateway_ip.get('network_id')
                raise q_exc.FixedIpAllocatedToGatewayIp(port_id=port_id,
                                                        network_id=network_id)
        port_fixed_ips = {}

        # Keep the ports and fixed ips that have not changed
        for port_id in remaining_port_ids:
            port = db_api.port_find(context, id=port_id, scope=db_api.ONE)
            fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id)
            port_fixed_ips[port_id] = {'port': port, 'fixed_ip': fixed_ip}

        # Disassociate the ports and fixed ips from the flip that were
        # associated to the flip but are not anymore
        for port_id in removed_port_ids:
            port = db_api.port_find(context, id=port_id, scope=db_api.ONE)
            flip = db_api.port_disassociate_ip(context, [port], flip)
            notifications[billing.IP_DISASSOC].add(flip)
            fixed_ip = _get_flip_fixed_ip_by_port_id(flip, port_id)
            if fixed_ip:
                flip = db_api.floating_ip_disassociate_fixed_ip(
                    context, flip, fixed_ip)

        # Validate the new ports with the flip and associate the new ports
        # and fixed ips with the flip
        for port_id in added_port_ids:
            port = db_api.port_find(context, id=port_id, scope=db_api.ONE)
            if not port:
                raise n_exc.PortNotFound(port_id=port_id)
            if any(ip for ip in port.ip_addresses
                   if (ip.get('address_type') == ip_types.FLOATING)):
                raise q_exc.PortAlreadyContainsFloatingIp(port_id=port_id)
            if any(ip for ip in port.ip_addresses
                   if (ip.get('address_type') == ip_types.SCALING)):
                raise q_exc.PortAlreadyContainsScalingIp(port_id=port_id)
            fixed_ip = _get_next_available_fixed_ip(port)
            LOG.info('new fixed ip: %s' % fixed_ip)
            if not fixed_ip:
                raise q_exc.NoAvailableFixedIpsForPort(port_id=port_id)
            port_fixed_ips[port_id] = {'port': port, 'fixed_ip': fixed_ip}
            flip = db_api.port_associate_ip(context, [port], flip, [port_id])
            notifications[billing.IP_ASSOC].add(flip)
            flip = db_api.floating_ip_associate_fixed_ip(
                context, flip, fixed_ip)

        flip_driver = registry.DRIVER_REGISTRY.get_driver()
        # If there are not any remaining ports and no new ones are being added,
        # remove the floating ip from unicorn
        if not remaining_port_ids and not added_port_ids:
            flip_driver.remove_floating_ip(flip)
        # If new ports are being added but there previously was not any ports,
        # then register a new floating ip with the driver because it is
        # assumed it does not exist
        elif added_port_ids and not curr_port_ids:
            flip_driver.register_floating_ip(flip, port_fixed_ips)
        else:
            flip_driver.update_floating_ip(flip, port_fixed_ips)
        context.session.commit()
    except Exception:
        context.session.rollback()
        raise

    # Send notifications for possible associate/disassociate events
    for notif_type, flip_set in notifications.iteritems():
        for flip in flip_set:
            billing.notify(context, notif_type, flip)

    # NOTE(blogan): ORM does not seem to update the model to the real state
    # of the database, so I'm doing an explicit refresh for now.
    context.session.refresh(flip)
    return flip
Пример #29
0
def update_port(context, id, port):
    """Update values of a port.

    : param context: neutron api request context
    : param id: UUID representing the port to update.
    : param port: dictionary with keys indicating fields to update.
        valid keys are those that have a value of True for 'allow_put'
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.
    """
    LOG.info("update_port %s for tenant %s" % (id, context.tenant_id))
    port_db = db_api.port_find(context, id=id, scope=db_api.ONE)
    if not port_db:
        raise n_exc.PortNotFound(port_id=id)

    port_dict = port["port"]
    fixed_ips = port_dict.pop("fixed_ips", None)

    admin_only = [
        "mac_address", "device_owner", "bridge", "admin_state_up", "device_id"
    ]
    always_filter = ["network_id", "backend_key", "network_plugin"]
    utils.filter_body(context,
                      port_dict,
                      admin_only=admin_only,
                      always_filter=always_filter)

    # Pre-check the requested fixed_ips before making too many db trips.
    # Note that this is the only check we need, since this call replaces
    # the entirety of the IP addresses document if fixed_ips are provided.
    if fixed_ips:
        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 fixed_ips_per_port=len(fixed_ips))

    new_security_groups = utils.pop_param(port_dict, "security_groups")
    if new_security_groups is not None:
        if (Capabilities.TENANT_NETWORK_SG
                not in CONF.QUARK.environment_capabilities):
            if not STRATEGY.is_provider_network(port_db["network_id"]):
                raise q_exc.TenantNetworkSecurityGroupRulesNotEnabled()

    if new_security_groups is not None and not port_db["device_id"]:
        raise q_exc.SecurityGroupsRequireDevice()

    group_ids, security_group_mods = _make_security_group_list(
        context, new_security_groups)
    quota.QUOTAS.limit_check(context,
                             context.tenant_id,
                             security_groups_per_port=len(group_ids))

    if fixed_ips is not None:
        # NOTE(mdietz): we want full control over IPAM since
        #              we're allocating by subnet instead of
        #              network.
        ipam_driver = ipam.IPAM_REGISTRY.get_strategy(
            ipam.QuarkIpamANY.get_name())

        addresses, subnet_ids = [], []
        ip_addresses = {}

        for fixed_ip in fixed_ips:
            subnet_id = fixed_ip.get("subnet_id")
            ip_address = fixed_ip.get("ip_address")
            if not (subnet_id or ip_address):
                raise n_exc.BadRequest(resource="fixed_ips",
                                       msg="subnet_id or ip_address required")

            if ip_address and not subnet_id:
                raise n_exc.BadRequest(
                    resource="fixed_ips",
                    msg="subnet_id required for ip_address allocation")

            if subnet_id and ip_address:
                ip_netaddr = None
                try:
                    ip_netaddr = netaddr.IPAddress(ip_address).ipv6()
                except netaddr.AddrFormatError:
                    raise n_exc.InvalidInput(
                        error_message="Invalid format provided for ip_address")
                ip_addresses[ip_netaddr] = subnet_id
            else:
                subnet_ids.append(subnet_id)

        port_ips = set([
            netaddr.IPAddress(int(a["address"]))
            for a in port_db["ip_addresses"]
        ])
        new_ips = set([a for a in ip_addresses.keys()])

        ips_to_allocate = list(new_ips - port_ips)
        ips_to_deallocate = list(port_ips - new_ips)

        for ip in ips_to_allocate:
            if ip in ip_addresses:
                # NOTE: Fix for RM10187 - we were losing the list of IPs if
                #       more than one IP was to be allocated. Track an
                #       aggregate list instead, and add it to the running total
                #       after each allocate
                allocated = []
                ipam_driver.allocate_ip_address(context,
                                                allocated,
                                                port_db["network_id"],
                                                port_db["id"],
                                                reuse_after=None,
                                                ip_addresses=[ip],
                                                subnets=[ip_addresses[ip]])
                addresses.extend(allocated)

        for ip in ips_to_deallocate:
            ipam_driver.deallocate_ips_by_port(context, port_db, ip_address=ip)

        for subnet_id in subnet_ids:
            ipam_driver.allocate_ip_address(
                context,
                addresses,
                port_db["network_id"],
                port_db["id"],
                reuse_after=CONF.QUARK.ipam_reuse_after,
                subnets=[subnet_id])

        # Need to return all existing addresses and the new ones
        if addresses:
            port_dict["addresses"] = port_db["ip_addresses"]
            port_dict["addresses"].extend(addresses)

    # NOTE(morgabra) Updating network_plugin on port objects is explicitly
    # disallowed in the api, so we use whatever exists in the db.
    net_driver = _get_net_driver(port_db.network, port=port_db)
    base_net_driver = _get_net_driver(port_db.network)

    # TODO(anyone): What do we want to have happen here if this fails? Is it
    #               ok to continue to keep the IPs but fail to apply security
    #               groups? Is there a clean way to have a multi-status? Since
    #               we're in a beta-y status, I'm going to let this sit for
    #               a future patch where we have time to solve it well.
    kwargs = {}
    if new_security_groups is not None:
        # TODO(anyone): this is kind of silly (when testing), because it will
        #               modify the incoming dict. Probably should be a copy or
        #               something.
        kwargs["security_groups"] = security_group_mods
    net_driver.update_port(context,
                           port_id=port_db["backend_key"],
                           mac_address=port_db["mac_address"],
                           device_id=port_db["device_id"],
                           base_net_driver=base_net_driver,
                           **kwargs)

    port_dict["security_groups"] = security_group_mods

    with context.session.begin():
        port = db_api.port_update(context, port_db, **port_dict)

    # NOTE(mdietz): fix for issue 112, we wanted the IPs to be in
    #              allocated_at order, so get a fresh object every time
    if port_db in context.session:
        context.session.expunge(port_db)
    port_db = db_api.port_find(context, id=id, scope=db_api.ONE)

    return v._make_port_dict(port_db)
Пример #30
0
 def test_prevent_l3_port_deletion_port_not_found(self, gp):
     # port not found doesn't prevent
     gp.return_value.get_port.side_effect = n_exc.PortNotFound(port_id='1')
     self.db.prevent_l3_port_deletion(None, None)