Hyper-V: remove driver from the neutron tree
The hyperv drivers and code should be part of the networking-hyperv project (https://github.com/openstack/networking-hyperv). A few changes are necessary in order to prevent Hyper-V deployments from breaking, especially when upgrading to Mitaka. Hyper-V deployments are configured to use the in-branch HyperVSecurityGroupsDriver. Removing it will cause the Hyper-V Neutron Agent to fail. If the agent is configured to use the old driver, the networking_hyperv's driver must be used instead and the users must be warned to update their configuration files to use the networking_hyperv's security groups driver. Removes the neutron-hyperv-agent entry point from setup.cfg. Removes the hyperv mechanism_driver from setup.cfg Moves the in-tree HyperVSecurityGroupsDriver to the networking_hyperv equivalent. Logs a warning if the in-tree HyperVSecurityGroupsDriver is used. Removes pywin32 and wmi requirements, as they've been included in networking_hyperv and they are Hyper-V specific requirements. Adds release note regarding the deprecated security groups driver. Co-Authored-By: Claudiu Belu <cbelu@cloudbasesolutions.com> Depends-On: I3a25f18b4f3a0621cb92b44eb61e434fa87e0aab Change-Id: I32451cba6933e88306a4308a07f3f0d1b81f626c Closes-bug: #1520054
This commit is contained in:
parent
770624b13b
commit
1b22c0e1ea
@ -1,44 +0,0 @@
|
|||||||
# Copyright 2013 Cloudbase Solutions SRL
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import log as logging
|
|
||||||
|
|
||||||
from neutron._i18n import _LI
|
|
||||||
from neutron.agent.common import config
|
|
||||||
from neutron.common import config as common_config
|
|
||||||
from neutron.plugins.hyperv.agent import config as hyperv_config
|
|
||||||
from neutron.plugins.hyperv.agent import l2_agent
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def register_options():
|
|
||||||
config.register_agent_state_opts_helper(cfg.CONF)
|
|
||||||
cfg.CONF.register_opts(hyperv_config.HYPERV_AGENT_OPTS, "AGENT")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
register_options()
|
|
||||||
common_config.init(sys.argv[1:])
|
|
||||||
config.setup_logging()
|
|
||||||
|
|
||||||
hyperv_agent = l2_agent.HyperVNeutronAgent()
|
|
||||||
|
|
||||||
# Start everything.
|
|
||||||
LOG.info(_LI("Agent initialized successfully, now running... "))
|
|
||||||
hyperv_agent.daemon_loop()
|
|
@ -37,7 +37,6 @@ import sqlalchemy as sa
|
|||||||
from sqlalchemy.sql import expression as sa_expr
|
from sqlalchemy.sql import expression as sa_expr
|
||||||
|
|
||||||
from neutron.plugins.common import constants as p_const
|
from neutron.plugins.common import constants as p_const
|
||||||
from neutron.plugins.ml2.drivers.hyperv import constants
|
|
||||||
|
|
||||||
FLAT_VLAN_ID = -1
|
FLAT_VLAN_ID = -1
|
||||||
LOCAL_VLAN_ID = -2
|
LOCAL_VLAN_ID = -2
|
||||||
@ -114,7 +113,7 @@ def _migrate_port_bindings(engine):
|
|||||||
sa_expr.select(['*'], from_obj=port_binding_ports))
|
sa_expr.select(['*'], from_obj=port_binding_ports))
|
||||||
ml2_bindings = [dict(x) for x in source_bindings]
|
ml2_bindings = [dict(x) for x in source_bindings]
|
||||||
for binding in ml2_bindings:
|
for binding in ml2_bindings:
|
||||||
binding['vif_type'] = constants.VIF_TYPE_HYPERV
|
binding['vif_type'] = 'hyperv'
|
||||||
binding['driver'] = HYPERV
|
binding['driver'] = HYPERV
|
||||||
segment = port_segment_map.get(binding['port_id'])
|
segment = port_segment_map.get(binding['port_id'])
|
||||||
if segment:
|
if segment:
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
# Copyright 2015 Cloudbase Solutions Srl
|
|
||||||
#
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
HYPERV_AGENT_OPTS = [
|
|
||||||
cfg.ListOpt(
|
|
||||||
'physical_network_vswitch_mappings',
|
|
||||||
default=[],
|
|
||||||
help=_('List of <physical_network>:<vswitch> '
|
|
||||||
'where the physical networks can be expressed with '
|
|
||||||
'wildcards, e.g.: ."*:external"')),
|
|
||||||
cfg.StrOpt(
|
|
||||||
'local_network_vswitch',
|
|
||||||
default='private',
|
|
||||||
help=_('Private vswitch name used for local networks')),
|
|
||||||
cfg.IntOpt('polling_interval', default=2,
|
|
||||||
help=_("The number of seconds the agent will wait between "
|
|
||||||
"polling for local device changes.")),
|
|
||||||
cfg.BoolOpt('enable_metrics_collection',
|
|
||||||
default=False,
|
|
||||||
help=_('Enables metrics collections for switch ports by using '
|
|
||||||
'Hyper-V\'s metric APIs. Collected data can by '
|
|
||||||
'retrieved by other apps and services, e.g.: '
|
|
||||||
'Ceilometer. Requires Hyper-V / Windows Server 2012 '
|
|
||||||
'and above')),
|
|
||||||
cfg.IntOpt('metrics_max_retries',
|
|
||||||
default=100,
|
|
||||||
help=_('Specifies the maximum number of retries to enable '
|
|
||||||
'Hyper-V\'s port metrics collection. The agent will try '
|
|
||||||
'to enable the feature once every polling_interval '
|
|
||||||
'period for at most metrics_max_retries or until it '
|
|
||||||
'succeedes.'))
|
|
||||||
]
|
|
@ -1,126 +0,0 @@
|
|||||||
# Copyright 2015 Cloudbase Solutions Srl
|
|
||||||
#
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import platform
|
|
||||||
|
|
||||||
from hyperv.neutron import hyperv_neutron_agent
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_log import log as logging
|
|
||||||
import oslo_messaging
|
|
||||||
from oslo_service import loopingcall
|
|
||||||
|
|
||||||
from neutron._i18n import _LE
|
|
||||||
from neutron.agent import rpc as agent_rpc
|
|
||||||
from neutron.agent import securitygroups_rpc as sg_rpc
|
|
||||||
from neutron.common import constants as n_const
|
|
||||||
from neutron.common import rpc as n_rpc
|
|
||||||
from neutron.common import topics
|
|
||||||
from neutron import context
|
|
||||||
from neutron.plugins.ml2.drivers.hyperv import constants as h_const
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
CONF = cfg.CONF
|
|
||||||
# Topic for tunnel notifications between the plugin and agent
|
|
||||||
TUNNEL = 'tunnel'
|
|
||||||
|
|
||||||
|
|
||||||
class HyperVSecurityAgent(sg_rpc.SecurityGroupAgentRpc):
|
|
||||||
|
|
||||||
def __init__(self, context, plugin_rpc):
|
|
||||||
super(HyperVSecurityAgent, self).__init__(context, plugin_rpc)
|
|
||||||
if sg_rpc.is_firewall_enabled():
|
|
||||||
self._setup_rpc()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def use_enhanced_rpc(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _setup_rpc(self):
|
|
||||||
self.topic = topics.AGENT
|
|
||||||
self.endpoints = [HyperVSecurityCallbackMixin(self)]
|
|
||||||
consumers = [[topics.SECURITY_GROUP, topics.UPDATE]]
|
|
||||||
|
|
||||||
self.connection = agent_rpc.create_consumers(self.endpoints,
|
|
||||||
self.topic,
|
|
||||||
consumers)
|
|
||||||
|
|
||||||
|
|
||||||
class HyperVSecurityCallbackMixin(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
|
|
||||||
|
|
||||||
target = oslo_messaging.Target(version='1.1')
|
|
||||||
|
|
||||||
def __init__(self, sg_agent):
|
|
||||||
super(HyperVSecurityCallbackMixin, self).__init__()
|
|
||||||
self.sg_agent = sg_agent
|
|
||||||
|
|
||||||
|
|
||||||
class HyperVNeutronAgent(hyperv_neutron_agent.HyperVNeutronAgentMixin):
|
|
||||||
# Set RPC API version to 1.1 by default.
|
|
||||||
target = oslo_messaging.Target(version='1.1')
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super(HyperVNeutronAgent, self).__init__(conf=CONF)
|
|
||||||
self._set_agent_state()
|
|
||||||
self._setup_rpc()
|
|
||||||
|
|
||||||
def _set_agent_state(self):
|
|
||||||
configurations = self.get_agent_configurations()
|
|
||||||
self.agent_state = {
|
|
||||||
'binary': 'neutron-hyperv-agent',
|
|
||||||
'host': CONF.host,
|
|
||||||
'topic': n_const.L2_AGENT_TOPIC,
|
|
||||||
'configurations': configurations,
|
|
||||||
'agent_type': h_const.AGENT_TYPE_HYPERV,
|
|
||||||
'start_flag': True}
|
|
||||||
|
|
||||||
def _report_state(self):
|
|
||||||
try:
|
|
||||||
self.state_rpc.report_state(self.context,
|
|
||||||
self.agent_state)
|
|
||||||
self.agent_state.pop('start_flag', None)
|
|
||||||
except Exception:
|
|
||||||
LOG.exception(_LE("Failed reporting state!"))
|
|
||||||
|
|
||||||
def _setup_rpc(self):
|
|
||||||
self.agent_id = 'hyperv_%s' % platform.node()
|
|
||||||
self.topic = topics.AGENT
|
|
||||||
self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)
|
|
||||||
self.sg_plugin_rpc = sg_rpc.SecurityGroupServerRpcApi(topics.PLUGIN)
|
|
||||||
|
|
||||||
self.state_rpc = agent_rpc.PluginReportStateAPI(topics.REPORTS)
|
|
||||||
|
|
||||||
# RPC network init
|
|
||||||
self.context = context.get_admin_context_without_session()
|
|
||||||
# Handle updates from service
|
|
||||||
self.endpoints = [self]
|
|
||||||
# Define the listening consumers for the agent
|
|
||||||
consumers = [[topics.PORT, topics.UPDATE],
|
|
||||||
[topics.NETWORK, topics.DELETE],
|
|
||||||
[topics.PORT, topics.DELETE],
|
|
||||||
[TUNNEL, topics.UPDATE]]
|
|
||||||
self.connection = agent_rpc.create_consumers(self.endpoints,
|
|
||||||
self.topic,
|
|
||||||
consumers)
|
|
||||||
|
|
||||||
self.client = n_rpc.get_client(self.target)
|
|
||||||
|
|
||||||
self.sec_groups_agent = HyperVSecurityAgent(
|
|
||||||
self.context, self.sg_plugin_rpc)
|
|
||||||
report_interval = CONF.AGENT.report_interval
|
|
||||||
if report_interval:
|
|
||||||
heartbeat = loopingcall.FixedIntervalLoopingCall(
|
|
||||||
self._report_state)
|
|
||||||
heartbeat.start(interval=report_interval)
|
|
@ -13,15 +13,22 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from debtcollector import moves
|
||||||
from hyperv.neutron import security_groups_driver as sg_driver
|
from hyperv.neutron import security_groups_driver as sg_driver
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from neutron.agent import firewall
|
from neutron.i18n import _LW
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
class HyperVSecurityGroupsDriver(sg_driver.HyperVSecurityGroupsDriverMixin,
|
# TODO(claudiub): Remove this module at the beginning of the O cycle.
|
||||||
firewall.FirewallDriver):
|
|
||||||
"""Security Groups Driver.
|
|
||||||
|
|
||||||
Security Groups implementation for Hyper-V VMs.
|
new_driver = 'hyperv.neutron.security_groups_driver.HyperVSecurityGroupsDriver'
|
||||||
"""
|
LOG.warn(_LW("You are using the deprecated firewall driver: %(deprecated)s. "
|
||||||
pass
|
"Use the recommended driver %(new)s instead."),
|
||||||
|
{'deprecated': '%s.HyperVSecurityGroupsDriver' % __name__,
|
||||||
|
'new': new_driver})
|
||||||
|
|
||||||
|
HyperVSecurityGroupsDriver = moves.moved_class(
|
||||||
|
sg_driver.HyperVSecurityGroupsDriver,
|
||||||
|
'HyperVSecurityGroupsDriver', __name__)
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
Hyper-V Neutron Agent and ML2 Mechanism Driver for ML2 Plugin
|
|
||||||
=============================================================
|
|
||||||
|
|
||||||
In order to properly use the Hyper-V Neutron Agent, neutron will have to use
|
|
||||||
the Ml2Plugin. This can be done by setting the ``core_plugin`` field in
|
|
||||||
``neutron.conf`` to:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
core_plugin = neutron.plugins.ml2.plugin.Ml2Plugin
|
|
||||||
|
|
||||||
Additionally, the ML2 Plugin must be configured to use the Hyper-V Mechanism
|
|
||||||
Driver, by adding it to the ``mechanism_drivers`` field in ``ml2_conf.ini``:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
[ml2]
|
|
||||||
mechanism_drivers = openvswitch,hyperv
|
|
||||||
# any other mechanism_drivers can be added to the list.
|
|
||||||
|
|
||||||
Currently, the mechanism driver supports the following network types: local,
|
|
||||||
flat, VLAN.
|
|
@ -1,17 +0,0 @@
|
|||||||
# Copyright (c) 2015 Thales Services SAS
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
AGENT_TYPE_HYPERV = 'HyperV agent'
|
|
||||||
VIF_TYPE_HYPERV = 'hyperv'
|
|
@ -1,37 +0,0 @@
|
|||||||
# Copyright (c) 2013 OpenStack Foundation
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from hyperv.neutron.ml2 import mech_hyperv
|
|
||||||
|
|
||||||
from neutron.extensions import portbindings
|
|
||||||
from neutron.plugins.ml2.drivers.hyperv import constants as constants
|
|
||||||
from neutron.plugins.ml2.drivers import mech_agent
|
|
||||||
|
|
||||||
|
|
||||||
class HypervMechanismDriver(mech_hyperv.HypervMechanismDriver,
|
|
||||||
mech_agent.SimpleAgentMechanismDriverBase):
|
|
||||||
"""Attach to networks using hyperv L2 agent.
|
|
||||||
|
|
||||||
The HypervMechanismDriver integrates the ml2 plugin with the
|
|
||||||
hyperv L2 agent. Port binding with this driver requires the hyperv
|
|
||||||
agent to be running on the port's host, and that agent to have
|
|
||||||
connectivity to at least one segment of the port's network.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super(HypervMechanismDriver, self).__init__(
|
|
||||||
constants.AGENT_TYPE_HYPERV,
|
|
||||||
constants.VIF_TYPE_HYPERV,
|
|
||||||
{portbindings.CAP_PORT_FILTER: False})
|
|
@ -1,6 +0,0 @@
|
|||||||
# The order of packages is significant, because pip processes them in the
|
|
||||||
# order
|
|
||||||
# of appearance. Changing the order has an impact on the overall integration
|
|
||||||
# process, which may cause wedges in the gate later.
|
|
||||||
|
|
||||||
networking-hyperv>=1.0.0
|
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- Hyper-V Neutron Agent has been fully decomposed from Neutron. Therefore, the
|
||||||
|
`neutron.plugins.hyperv.agent.security_groups_driver.HyperVSecurityGroupsDriver`
|
||||||
|
firewall driver has been deprecated and will be removed in the O cycle.
|
||||||
|
Update the `neutron_hyperv_agent.conf` files on the Hyper-V nodes to
|
||||||
|
use `hyperv.neutron.security_groups_driver.HyperVSecurityGroupsDriver`,
|
||||||
|
which is the networking_hyperv security groups driver.
|
@ -41,7 +41,3 @@ oslo.utils>=2.8.0 # Apache-2.0
|
|||||||
oslo.versionedobjects>=0.13.0
|
oslo.versionedobjects>=0.13.0
|
||||||
|
|
||||||
python-novaclient!=2.33.0,>=2.29.0
|
python-novaclient!=2.33.0,>=2.29.0
|
||||||
|
|
||||||
# Windows-only requirements
|
|
||||||
pywin32;sys_platform=='win32'
|
|
||||||
wmi;sys_platform=='win32'
|
|
||||||
|
@ -65,7 +65,6 @@ console_scripts =
|
|||||||
neutron-db-manage = neutron.db.migration.cli:main
|
neutron-db-manage = neutron.db.migration.cli:main
|
||||||
neutron-debug = neutron.debug.shell:main
|
neutron-debug = neutron.debug.shell:main
|
||||||
neutron-dhcp-agent = neutron.cmd.eventlet.agents.dhcp:main
|
neutron-dhcp-agent = neutron.cmd.eventlet.agents.dhcp:main
|
||||||
neutron-hyperv-agent = neutron.cmd.eventlet.plugins.hyperv_neutron_agent:main
|
|
||||||
neutron-keepalived-state-change = neutron.cmd.keepalived_state_change:main
|
neutron-keepalived-state-change = neutron.cmd.keepalived_state_change:main
|
||||||
neutron-ipset-cleanup = neutron.cmd.ipset_cleanup:main
|
neutron-ipset-cleanup = neutron.cmd.ipset_cleanup:main
|
||||||
neutron-l3-agent = neutron.cmd.eventlet.agents.l3:main
|
neutron-l3-agent = neutron.cmd.eventlet.agents.l3:main
|
||||||
@ -118,7 +117,6 @@ neutron.ml2.mechanism_drivers =
|
|||||||
test = neutron.tests.unit.plugins.ml2.drivers.mechanism_test:TestMechanismDriver
|
test = neutron.tests.unit.plugins.ml2.drivers.mechanism_test:TestMechanismDriver
|
||||||
linuxbridge = neutron.plugins.ml2.drivers.linuxbridge.mech_driver.mech_linuxbridge:LinuxbridgeMechanismDriver
|
linuxbridge = neutron.plugins.ml2.drivers.linuxbridge.mech_driver.mech_linuxbridge:LinuxbridgeMechanismDriver
|
||||||
openvswitch = neutron.plugins.ml2.drivers.openvswitch.mech_driver.mech_openvswitch:OpenvswitchMechanismDriver
|
openvswitch = neutron.plugins.ml2.drivers.openvswitch.mech_driver.mech_openvswitch:OpenvswitchMechanismDriver
|
||||||
hyperv = neutron.plugins.ml2.drivers.hyperv.mech_hyperv:HypervMechanismDriver
|
|
||||||
l2population = neutron.plugins.ml2.drivers.l2pop.mech_driver:L2populationMechanismDriver
|
l2population = neutron.plugins.ml2.drivers.l2pop.mech_driver:L2populationMechanismDriver
|
||||||
ofagent = neutron.plugins.ml2.drivers.ofagent.driver:OfagentMechanismDriver
|
ofagent = neutron.plugins.ml2.drivers.ofagent.driver:OfagentMechanismDriver
|
||||||
brocade = networking_brocade.vdx.ml2driver.mechanism_brocade:BrocadeMechanism
|
brocade = networking_brocade.vdx.ml2driver.mechanism_brocade:BrocadeMechanism
|
||||||
|
Loading…
Reference in New Issue
Block a user