Merge "TVD: fix plugin apis to allow CI job to succeed"
This commit is contained in:
		@@ -16,7 +16,6 @@
 | 
				
			|||||||
import uuid
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef
 | 
					from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef
 | 
				
			||||||
from neutron_lib.api.definitions import port as port_def
 | 
					 | 
				
			||||||
from neutron_lib.api.definitions import port_security as psec
 | 
					from neutron_lib.api.definitions import port_security as psec
 | 
				
			||||||
from neutron_lib.exceptions import allowedaddresspairs as addr_exc
 | 
					from neutron_lib.exceptions import allowedaddresspairs as addr_exc
 | 
				
			||||||
from neutron_lib.exceptions import port_security as psec_exc
 | 
					from neutron_lib.exceptions import port_security as psec_exc
 | 
				
			||||||
@@ -133,8 +132,8 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    @resource_extend.extends([port_def.COLLECTION_NAME])
 | 
					 | 
				
			||||||
    def _extend_port_dict_binding(result, portdb):
 | 
					    def _extend_port_dict_binding(result, portdb):
 | 
				
			||||||
 | 
					        LOG.error("DEBUG ADIT DVS _extend_port_dict_binding")
 | 
				
			||||||
        result[pbin.VIF_TYPE] = nsx_constants.VIF_TYPE_DVS
 | 
					        result[pbin.VIF_TYPE] = nsx_constants.VIF_TYPE_DVS
 | 
				
			||||||
        port_attr = portdb.get('nsx_port_attributes')
 | 
					        port_attr = portdb.get('nsx_port_attributes')
 | 
				
			||||||
        if port_attr:
 | 
					        if port_attr:
 | 
				
			||||||
@@ -432,6 +431,7 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        # latest db model for the extension functions
 | 
					        # latest db model for the extension functions
 | 
				
			||||||
        port_model = self._get_port(context, port_data['id'])
 | 
					        port_model = self._get_port(context, port_data['id'])
 | 
				
			||||||
        resource_extend.apply_funcs('ports', port_data, port_model)
 | 
					        resource_extend.apply_funcs('ports', port_data, port_model)
 | 
				
			||||||
 | 
					        self._extend_port_dict_binding(port_data, port_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.handle_port_dhcp_access(context, port_data, action='create_port')
 | 
					        self.handle_port_dhcp_access(context, port_data, action='create_port')
 | 
				
			||||||
        return port_data
 | 
					        return port_data
 | 
				
			||||||
@@ -507,6 +507,16 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        self.handle_port_dhcp_access(
 | 
					        self.handle_port_dhcp_access(
 | 
				
			||||||
            context, neutron_db_port, action='delete_port')
 | 
					            context, neutron_db_port, action='delete_port')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_port(self, context, id, fields=None):
 | 
				
			||||||
 | 
					        port = super(NsxDvsV2, self).get_port(context, id, fields=None)
 | 
				
			||||||
 | 
					        if 'id' in port:
 | 
				
			||||||
 | 
					            port_model = self._get_port(context, port['id'])
 | 
				
			||||||
 | 
					            resource_extend.apply_funcs('ports', port, port_model)
 | 
				
			||||||
 | 
					            self._extend_port_dict_binding(port, port_model)
 | 
				
			||||||
 | 
					        self._extend_get_port_dict_qos_and_binding(context, port)
 | 
				
			||||||
 | 
					        self._remove_provider_security_groups_from_list(port)
 | 
				
			||||||
 | 
					        return db_utils.resource_fields(port, fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_router(self, context, router):
 | 
					    def create_router(self, context, router):
 | 
				
			||||||
        # DVS backend cannot support logical router
 | 
					        # DVS backend cannot support logical router
 | 
				
			||||||
        msg = (_("Unable to create router %s with DVS") %
 | 
					        msg = (_("Unable to create router %s with DVS") %
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,20 +16,27 @@
 | 
				
			|||||||
from neutron_lib.api.definitions import network as net_def
 | 
					from neutron_lib.api.definitions import network as net_def
 | 
				
			||||||
from neutron_lib.api.definitions import port as port_def
 | 
					from neutron_lib.api.definitions import port as port_def
 | 
				
			||||||
from neutron_lib.api.definitions import subnet as subnet_def
 | 
					from neutron_lib.api.definitions import subnet as subnet_def
 | 
				
			||||||
 | 
					from neutron_lib.callbacks import events
 | 
				
			||||||
 | 
					from neutron_lib.callbacks import registry
 | 
				
			||||||
 | 
					from neutron_lib.callbacks import resources
 | 
				
			||||||
from neutron_lib import context as n_context
 | 
					from neutron_lib import context as n_context
 | 
				
			||||||
 | 
					from neutron_lib.plugins import constants as plugin_constants
 | 
				
			||||||
from neutron_lib.plugins import directory
 | 
					from neutron_lib.plugins import directory
 | 
				
			||||||
from oslo_config import cfg
 | 
					from oslo_config import cfg
 | 
				
			||||||
from oslo_log import log as logging
 | 
					from oslo_log import log as logging
 | 
				
			||||||
 | 
					from oslo_utils import excutils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from neutron.db import _resource_extend as resource_extend
 | 
					from neutron.db import _resource_extend as resource_extend
 | 
				
			||||||
from neutron.db import _utils as db_utils
 | 
					from neutron.db import _utils as db_utils
 | 
				
			||||||
from neutron.db import agents_db
 | 
					from neutron.db import agents_db
 | 
				
			||||||
 | 
					from neutron.db import agentschedulers_db
 | 
				
			||||||
from neutron.db import allowedaddresspairs_db as addr_pair_db
 | 
					from neutron.db import allowedaddresspairs_db as addr_pair_db
 | 
				
			||||||
from neutron.db import api as db_api
 | 
					from neutron.db import api as db_api
 | 
				
			||||||
from neutron.db.availability_zone import router as router_az_db
 | 
					from neutron.db.availability_zone import router as router_az_db
 | 
				
			||||||
from neutron.db import external_net_db
 | 
					from neutron.db import external_net_db
 | 
				
			||||||
from neutron.db import extradhcpopt_db
 | 
					from neutron.db import extradhcpopt_db
 | 
				
			||||||
from neutron.db import extraroute_db
 | 
					from neutron.db import extraroute_db
 | 
				
			||||||
 | 
					from neutron.db import l3_db
 | 
				
			||||||
from neutron.db import l3_gwmode_db
 | 
					from neutron.db import l3_gwmode_db
 | 
				
			||||||
from neutron.db.models import l3 as l3_db_models
 | 
					from neutron.db.models import l3 as l3_db_models
 | 
				
			||||||
from neutron.db.models import securitygroup as securitygroup_model  # noqa
 | 
					from neutron.db.models import securitygroup as securitygroup_model  # noqa
 | 
				
			||||||
@@ -61,7 +68,8 @@ TVD_PLUGIN_TYPE = "Nsx-TVD"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@resource_extend.has_resource_extenders
 | 
					@resource_extend.has_resource_extenders
 | 
				
			||||||
class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
					class NsxTVDPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
 | 
				
			||||||
 | 
					                   addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			||||||
                   agents_db.AgentDbMixin,
 | 
					                   agents_db.AgentDbMixin,
 | 
				
			||||||
                   nsx_plugin_common.NsxPluginBase,
 | 
					                   nsx_plugin_common.NsxPluginBase,
 | 
				
			||||||
                   rt_rtr.RouterType_mixin,
 | 
					                   rt_rtr.RouterType_mixin,
 | 
				
			||||||
@@ -78,7 +86,7 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    supported_extension_aliases = ['project-plugin-map']
 | 
					    supported_extension_aliases = ['project-plugin-map']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __native_bulk_support = False
 | 
					    __native_bulk_support = True
 | 
				
			||||||
    __native_pagination_support = True
 | 
					    __native_pagination_support = True
 | 
				
			||||||
    __native_sorting_support = True
 | 
					    __native_sorting_support = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -106,6 +114,8 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        self.init_extensions()
 | 
					        self.init_extensions()
 | 
				
			||||||
        self.lbv2_driver = lb_driver_v2.EdgeLoadbalancerDriverV2()
 | 
					        self.lbv2_driver = lb_driver_v2.EdgeLoadbalancerDriverV2()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._unsubscribe_callback_events()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def plugin_type():
 | 
					    def plugin_type():
 | 
				
			||||||
        return TVD_PLUGIN_TYPE
 | 
					        return TVD_PLUGIN_TYPE
 | 
				
			||||||
@@ -183,6 +193,36 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
                self._unsupported_fields[plugin_type]['port'] = [
 | 
					                self._unsupported_fields[plugin_type]['port'] = [
 | 
				
			||||||
                    'mac_learning_enabled', 'provider_security_groups']
 | 
					                    'mac_learning_enabled', 'provider_security_groups']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _unsubscribe_callback_events(self):
 | 
				
			||||||
 | 
					        # unsubscribe the callback that should be called on all plugins
 | 
				
			||||||
 | 
					        # other that NSX-T.
 | 
				
			||||||
 | 
					        registry.unsubscribe_all(
 | 
				
			||||||
 | 
					            l3_db.L3_NAT_dbonly_mixin._prevent_l3_port_delete_callback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Instead we will subscribe our internal callback.
 | 
				
			||||||
 | 
					        registry.subscribe(self._prevent_l3_port_delete_callback,
 | 
				
			||||||
 | 
					                           resources.PORT, events.BEFORE_DELETE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def _prevent_l3_port_delete_callback(resource, event, trigger, **kwargs):
 | 
				
			||||||
 | 
					        """Register a callback to replace the default one
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This callback will prevent port deleting only if the port plugin
 | 
				
			||||||
 | 
					        is not NSX-T (in NSX-T plugin it was already handled)
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        context = kwargs['context']
 | 
				
			||||||
 | 
					        port_id = kwargs['port_id']
 | 
				
			||||||
 | 
					        port_check = kwargs['port_check']
 | 
				
			||||||
 | 
					        l3plugin = directory.get_plugin(plugin_constants.L3)
 | 
				
			||||||
 | 
					        if l3plugin and port_check:
 | 
				
			||||||
 | 
					            # if not nsx-t - call super code
 | 
				
			||||||
 | 
					            core_plugin = directory.get_plugin()
 | 
				
			||||||
 | 
					            db_port = core_plugin._get_port(context, port_id)
 | 
				
			||||||
 | 
					            p = core_plugin._get_plugin_from_net_id(
 | 
				
			||||||
 | 
					                context, db_port['network_id'])
 | 
				
			||||||
 | 
					            if p.plugin_type() != projectpluginmap.NsxPlugins.NSX_T:
 | 
				
			||||||
 | 
					                l3plugin.prevent_l3_port_deletion(context, port_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _validate_obj_extensions(self, data, plugin_type, obj_type):
 | 
					    def _validate_obj_extensions(self, data, plugin_type, obj_type):
 | 
				
			||||||
        """prevent configuration of unsupported extensions"""
 | 
					        """prevent configuration of unsupported extensions"""
 | 
				
			||||||
        for field in self._unsupported_fields[plugin_type][obj_type]:
 | 
					        for field in self._unsupported_fields[plugin_type][obj_type]:
 | 
				
			||||||
@@ -228,6 +268,46 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        p = self._get_plugin_from_project(context, tenant_id)
 | 
					        p = self._get_plugin_from_project(context, tenant_id)
 | 
				
			||||||
        return p.create_network(context, network)
 | 
					        return p.create_network(context, network)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _create_bulk(self, resource, context, request_items):
 | 
				
			||||||
 | 
					        objects = []
 | 
				
			||||||
 | 
					        collection = "%ss" % resource
 | 
				
			||||||
 | 
					        items = request_items[collection]
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            with db_api.context_manager.writer.using(context):
 | 
				
			||||||
 | 
					                for item in items:
 | 
				
			||||||
 | 
					                    obj_creator = getattr(self, 'create_%s' % resource)
 | 
				
			||||||
 | 
					                    objects.append(obj_creator(context, item))
 | 
				
			||||||
 | 
					        except Exception:
 | 
				
			||||||
 | 
					            with excutils.save_and_reraise_exception():
 | 
				
			||||||
 | 
					                LOG.error("An exception occurred while creating "
 | 
				
			||||||
 | 
					                          "the %(resource)s:%(item)s",
 | 
				
			||||||
 | 
					                          {'resource': resource, 'item': item})
 | 
				
			||||||
 | 
					        return objects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @db_api.retry_if_session_inactive()
 | 
				
			||||||
 | 
					    def create_network_bulk(self, context, networks):
 | 
				
			||||||
 | 
					        #Implement create bulk so that the plugin calculation will be done once
 | 
				
			||||||
 | 
					        objects = []
 | 
				
			||||||
 | 
					        items = networks['networks']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # look at the first network to find out the project & plugin
 | 
				
			||||||
 | 
					        net_data = items[0]['network']
 | 
				
			||||||
 | 
					        tenant_id = net_data['tenant_id']
 | 
				
			||||||
 | 
					        self._ensure_default_security_group(context, tenant_id)
 | 
				
			||||||
 | 
					        p = self._get_plugin_from_project(context, tenant_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # create all networks one by one
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            with db_api.context_manager.writer.using(context):
 | 
				
			||||||
 | 
					                for item in items:
 | 
				
			||||||
 | 
					                    objects.append(p.create_network(context, item))
 | 
				
			||||||
 | 
					        except Exception:
 | 
				
			||||||
 | 
					            with excutils.save_and_reraise_exception():
 | 
				
			||||||
 | 
					                LOG.error("An exception occurred while creating "
 | 
				
			||||||
 | 
					                          "the networks:%(item)s",
 | 
				
			||||||
 | 
					                          {'item': item})
 | 
				
			||||||
 | 
					        return objects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete_network(self, context, id):
 | 
					    def delete_network(self, context, id):
 | 
				
			||||||
        p = self._get_plugin_from_net_id(context, id)
 | 
					        p = self._get_plugin_from_net_id(context, id)
 | 
				
			||||||
        p.delete_network(context, id)
 | 
					        p.delete_network(context, id)
 | 
				
			||||||
@@ -454,11 +534,11 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        p = self._get_plugin_from_net_id(context, net_id)
 | 
					        p = self._get_plugin_from_net_id(context, net_id)
 | 
				
			||||||
        return p.delete_floatingip(context, id)
 | 
					        return p.delete_floatingip(context, id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_floatingip(self, context, id):
 | 
					    def get_floatingip(self, context, id, fields=None):
 | 
				
			||||||
        fip = self._get_floatingip(context, id)
 | 
					        fip = self._get_floatingip(context, id)
 | 
				
			||||||
        net_id = fip['floating_network_id']
 | 
					        net_id = fip['floating_network_id']
 | 
				
			||||||
        p = self._get_plugin_from_net_id(context, net_id)
 | 
					        p = self._get_plugin_from_net_id(context, net_id)
 | 
				
			||||||
        return p.get_floatingip(context, id)
 | 
					        return p.get_floatingip(context, id, fields=fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def disassociate_floatingips(self, context, port_id):
 | 
					    def disassociate_floatingips(self, context, port_id):
 | 
				
			||||||
        db_port = self._get_port(context, port_id)
 | 
					        db_port = self._get_port(context, port_id)
 | 
				
			||||||
@@ -490,9 +570,9 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        p = self._get_plugin_from_sg_id(context, id)
 | 
					        p = self._get_plugin_from_sg_id(context, id)
 | 
				
			||||||
        return p.update_security_group(context, id, security_group)
 | 
					        return p.update_security_group(context, id, security_group)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_security_group(self, context, id):
 | 
					    def get_security_group(self, context, id, fields=None):
 | 
				
			||||||
        p = self._get_plugin_from_sg_id(context, id)
 | 
					        p = self._get_plugin_from_sg_id(context, id)
 | 
				
			||||||
        return p.get_security_group(context, id)
 | 
					        return p.get_security_group(context, id, fields=fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_security_group_rule_bulk(self, context, security_group_rules):
 | 
					    def create_security_group_rule_bulk(self, context, security_group_rules):
 | 
				
			||||||
        p = self._get_plugin_from_project(context, context.project_id)
 | 
					        p = self._get_plugin_from_project(context, context.project_id)
 | 
				
			||||||
@@ -504,7 +584,9 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        return p.create_security_group_rule(context, security_group_rule)
 | 
					        return p.create_security_group_rule(context, security_group_rule)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete_security_group_rule(self, context, id):
 | 
					    def delete_security_group_rule(self, context, id):
 | 
				
			||||||
        p = self._get_plugin_from_sg_id(context, id)
 | 
					        rule_db = self._get_security_group_rule(context, id)
 | 
				
			||||||
 | 
					        sg_id = rule_db['security_group_id']
 | 
				
			||||||
 | 
					        p = self._get_plugin_from_sg_id(context, sg_id)
 | 
				
			||||||
        p.delete_security_group_rule(context, id)
 | 
					        p.delete_security_group_rule(context, id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
@@ -582,14 +664,26 @@ class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
 | 
				
			|||||||
        If not there - add an entry with the default plugin
 | 
					        If not there - add an entry with the default plugin
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        plugin_type = self.default_plugin
 | 
					        plugin_type = self.default_plugin
 | 
				
			||||||
 | 
					        if not project_id:
 | 
				
			||||||
 | 
					            # if the project_id is empty - return the default one and do not
 | 
				
			||||||
 | 
					            # add to db (used by admin context to get actions)
 | 
				
			||||||
 | 
					            return plugin_type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mapping = nsx_db.get_project_plugin_mapping(
 | 
					        mapping = nsx_db.get_project_plugin_mapping(
 | 
				
			||||||
            context.session, project_id)
 | 
					            context.session, project_id)
 | 
				
			||||||
        if mapping:
 | 
					        if mapping:
 | 
				
			||||||
            plugin_type = mapping['plugin']
 | 
					            plugin_type = mapping['plugin']
 | 
				
			||||||
        elif project_id:
 | 
					        else:
 | 
				
			||||||
 | 
					            # add a new entry with the default plugin
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                # TODO(asarfaty) we get timeout here when called under
 | 
				
			||||||
 | 
					                # _ext_extend_network_dict of the first create_network
 | 
				
			||||||
                self.create_project_plugin_map(context,
 | 
					                self.create_project_plugin_map(context,
 | 
				
			||||||
                    {'project_plugin_map': {'plugin': plugin_type,
 | 
					                    {'project_plugin_map': {'plugin': plugin_type,
 | 
				
			||||||
                                            'project': project_id}})
 | 
					                                            'project': project_id}})
 | 
				
			||||||
 | 
					            except projectpluginmap.ProjectPluginAlreadyExists:
 | 
				
			||||||
 | 
					                # Maybe added by another thread
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
        if not self.plugins.get(plugin_type):
 | 
					        if not self.plugins.get(plugin_type):
 | 
				
			||||||
            msg = (_("Cannot use unsupported plugin %(plugin)s for project "
 | 
					            msg = (_("Cannot use unsupported plugin %(plugin)s for project "
 | 
				
			||||||
                     "%(project)s") % {'plugin': plugin_type,
 | 
					                     "%(project)s") % {'plugin': plugin_type,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -127,7 +127,7 @@ class NsxVMetadataProxyHandler(object):
 | 
				
			|||||||
                    core_plugin.create_project_plugin_map(
 | 
					                    core_plugin.create_project_plugin_map(
 | 
				
			||||||
                        context,
 | 
					                        context,
 | 
				
			||||||
                        {'project_plugin_map':
 | 
					                        {'project_plugin_map':
 | 
				
			||||||
                            {'plugin': projectpluginmap.NsxPlugins.NSX_T,
 | 
					                            {'plugin': projectpluginmap.NsxPlugins.NSX_V,
 | 
				
			||||||
                             'project': nsxv_constants.INTERNAL_TENANT_ID}})
 | 
					                             'project': nsxv_constants.INTERNAL_TENANT_ID}})
 | 
				
			||||||
                except projectpluginmap.ProjectPluginAlreadyExists:
 | 
					                except projectpluginmap.ProjectPluginAlreadyExists:
 | 
				
			||||||
                    pass
 | 
					                    pass
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user