Ejemplo n.º 1
0
    def update_floatingip_port_forwarding(self, context, id, floatingip_id,
                                          port_forwarding):
        port_forwarding = port_forwarding.get(apidef.RESOURCE_NAME)
        new_internal_port_id = None
        if port_forwarding and port_forwarding.get('internal_port_id'):
            new_internal_port_id = port_forwarding.get('internal_port_id')
            self._check_port_has_binding_floating_ip(context, port_forwarding)

        try:
            with db_api.CONTEXT_WRITER.using(context):
                fip_obj = self._get_fip_obj(context, floatingip_id)
                pf_obj = pf.PortForwarding.get_object(context, id=id)
                if not pf_obj:
                    raise pf_exc.PortForwardingNotFound(id=id)
                original_pf_obj = copy.deepcopy(pf_obj)
                ori_internal_port_id = pf_obj.internal_port_id
                if new_internal_port_id and (new_internal_port_id !=
                                             ori_internal_port_id):
                    router_id = self._find_a_router_for_fip_port_forwarding(
                        context, port_forwarding, fip_obj)
                    self._check_router_match(context, fip_obj, router_id,
                                             port_forwarding)

                # As the socket will update when dict contains
                # internal_ip_address and internal_port.
                internal_ip_address = port_forwarding.get(
                    'internal_ip_address')
                internal_port = port_forwarding.get('internal_port')
                if any([internal_ip_address, internal_port]):
                    port_forwarding.update({
                        'internal_ip_address':
                        internal_ip_address if internal_ip_address else str(
                            pf_obj.internal_ip_address),
                        'internal_port':
                        internal_port
                        if internal_port else pf_obj.internal_port
                    })
                pf_obj.update_fields(port_forwarding, reset_changes=True)
                self._check_port_forwarding_update(context, pf_obj)
                pf_obj.update()
        except obj_exc.NeutronDbObjectDuplicateEntry:
            (__, conflict_params) = self._find_existing_port_forwarding(
                context, floatingip_id, pf_obj.to_dict())
            message = _("A duplicate port forwarding entry with same "
                        "attributes already exists, conflicting values "
                        "are %s") % conflict_params
            raise lib_exc.BadRequest(resource=apidef.RESOURCE_NAME,
                                     msg=message)
        if self._rpc_notifications_required:
            self.push_api.push(context, [pf_obj], rpc_events.UPDATED)
        registry.notify(pf_consts.PORT_FORWARDING,
                        events.AFTER_UPDATE,
                        self,
                        payload=[
                            callbacks.PortForwardingPayload(
                                context,
                                current_pf=pf_obj,
                                original_pf=original_pf_obj)
                        ])
        return pf_obj
Ejemplo n.º 2
0
    def create_floatingip_port_forwarding(self, context, floatingip_id,
                                          port_forwarding):
        port_forwarding = port_forwarding.get(apidef.RESOURCE_NAME)
        port_forwarding['floatingip_id'] = floatingip_id

        self._check_port_has_binding_floating_ip(context, port_forwarding)
        with db_api.CONTEXT_WRITER.using(context):
            fip_obj = self._get_fip_obj(context, floatingip_id)
            if fip_obj.fixed_port_id:
                raise lib_l3_exc.FloatingIPPortAlreadyAssociated(
                    port_id=port_forwarding['internal_port_id'],
                    fip_id=fip_obj.id,
                    floating_ip_address=fip_obj.floating_ip_address,
                    fixed_ip=str(port_forwarding['internal_ip_address']),
                    net_id=fip_obj.floating_network_id)
            router_id = self._find_a_router_for_fip_port_forwarding(
                context, port_forwarding, fip_obj)
            pf_obj = pf.PortForwarding(context, **port_forwarding)

            # If this func does not raise an exception, means the
            # router_id matched.
            # case1: fip_obj.router_id = None
            # case2: fip_obj.router_id is the same with we selected.
            self._check_router_match(context, fip_obj, router_id,
                                     port_forwarding)

            if not fip_obj.router_id:
                values = {'router_id': router_id, 'fixed_port_id': None}
                l3_obj.FloatingIP.update_objects(context,
                                                 values,
                                                 id=floatingip_id)
            try:
                pf_obj.create()
            except obj_exc.NeutronDbObjectDuplicateEntry:
                (__, conflict_params) = self._find_existing_port_forwarding(
                    context, floatingip_id, port_forwarding)
                message = _("A duplicate port forwarding entry with same "
                            "attributes already exists, conflicting "
                            "values are %s") % conflict_params
                raise lib_exc.BadRequest(resource=apidef.RESOURCE_NAME,
                                         msg=message)

        registry.notify(pf_consts.PORT_FORWARDING,
                        events.AFTER_CREATE,
                        self,
                        payload=[
                            callbacks.PortForwardingPayload(context,
                                                            current_pf=pf_obj)
                        ])

        if self._rpc_notifications_required:
            self.push_api.push(context, [pf_obj], rpc_events.CREATED)

        return pf_obj
Ejemplo n.º 3
0
    def delete_floatingip_port_forwarding(self, context, id, floatingip_id):
        pf_obj = pf.PortForwarding.get_object(context, id=id)

        if not pf_obj or pf_obj.floatingip_id != floatingip_id:
            raise pf_exc.PortForwardingNotFound(id=id)
        with db_api.CONTEXT_WRITER.using(context):
            fip_obj = self._get_fip_obj(context, pf_obj.floatingip_id)
            pf_objs = pf.PortForwarding.get_objects(
                context, floatingip_id=pf_obj.floatingip_id)
            if len(pf_objs) == 1 and pf_objs[0].id == pf_obj.id:
                fip_obj.update_fields({'router_id': None})
                fip_obj.update()
            pf_obj.delete()
        if self._rpc_notifications_required:
            self.push_api.push(context, [pf_obj], rpc_events.DELETED)
        registry.notify(pf_consts.PORT_FORWARDING, events.AFTER_DELETE, self,
                        payload=[callbacks.PortForwardingPayload(
                            context, original_pf=pf_obj)])
Ejemplo n.º 4
0
    def _process_port_request(self, resource, event, trigger, context,
                              **kwargs):
        # Deleting floatingip will receive port resource with precommit_delete
        # event, so just return, then check the request in
        # _check_floatingip_request callback.
        if kwargs['port']['device_owner'].startswith(
                lib_consts.DEVICE_OWNER_FLOATINGIP):
            return

        # This block is used for checking if there are some fixed ips updates.
        # Whatever the event is AFTER_UPDATE/PRECOMMIT_DELETE,
        # we will use the update_ip_set for checking if the possible associated
        # port forwarding resources need to be deleted for port's AFTER_UPDATE
        # event. Or get all affected ip addresses for port's PRECOMMIT_DELETE
        # event.
        port_id = kwargs['port']['id']
        update_fixed_ips = kwargs['port']['fixed_ips']
        update_ip_set = set()
        for update_fixed_ip in update_fixed_ips:
            if (netaddr.IPNetwork(update_fixed_ip.get('ip_address')).version ==
                    lib_consts.IP_VERSION_4):
                update_ip_set.add(update_fixed_ip.get('ip_address'))
        if not update_ip_set:
            return

        # If the port owner wants to update or delete port, we must elevate the
        # context to check if the floatingip or port forwarding resources
        # are owned by other tenants.
        if not context.is_admin:
            context = context.elevated()
        # If the logic arrives here, that means we have got update_ip_set and
        # its value is not None. So we need to get all port forwarding
        # resources based on the request port_id for preparing the next
        # process, such as deleting them.
        pf_resources = pf.PortForwarding.get_objects(context,
                                                     internal_port_id=port_id)
        if not pf_resources:
            return

        # If the logic arrives here, that means we have got pf_resources and
        # its value is not None either. Then we collect all ip addresses
        # which are used by port forwarding resources to generate used_ip_set,
        # and we default to set remove_ip_set as used_ip_set which means we
        # want to delete all port forwarding resources when event is
        # PRECOMMIT_DELETE. And when event is AFTER_UPDATE, we get the
        # different part.
        used_ip_set = set()
        for pf_resource in pf_resources:
            used_ip_set.add(str(pf_resource.internal_ip_address))
        remove_ip_set = used_ip_set
        if event == events.AFTER_UPDATE:
            remove_ip_set = used_ip_set - update_ip_set
            if not remove_ip_set:
                return

        # Here, we get the remove_ip_set, the following block will delete the
        # port forwarding resources based on remove_ip_set. Just need to note
        # here, if event is AFTER_UPDATE, and remove_ip_set is empty, the
        # following block won't be processed.
        remove_port_forwarding_list = []
        with db_api.CONTEXT_WRITER.using(context):
            for pf_resource in pf_resources:
                if str(pf_resource.internal_ip_address) in remove_ip_set:
                    pf_objs = pf.PortForwarding.get_objects(
                        context, floatingip_id=pf_resource.floatingip_id)
                    if len(pf_objs) == 1 and pf_objs[0].id == pf_resource.id:
                        fip_obj = l3_obj.FloatingIP.get_object(
                            context, id=pf_resource.floatingip_id)
                        fip_obj.update_fields({'router_id': None})
                        fip_obj.update()
                    pf_resource.delete()
                    remove_port_forwarding_list.append(pf_resource)

        if self._rpc_notifications_required:
            self.push_api.push(context, remove_port_forwarding_list,
                               rpc_events.DELETED)
        registry_notify_payload = [
            callbacks.PortForwardingPayload(context, original_pf=pf_obj)
            for pf_obj in remove_port_forwarding_list
        ]
        registry.notify(pf_consts.PORT_FORWARDING,
                        events.AFTER_DELETE,
                        self,
                        payload=registry_notify_payload)