Remove resource_setup skip checks
Removes resource_setup checks that were validating the number of enabled compute nodes. It also removes the waiting for compute nodes to set up. This is not part of the test class resource configuration. Test classes now only skip tests if the min_compute_nodes is less than the required to run. All tests that needs at least 1 compute node enabled will now check and fail at the start of the test. This patch also improves some action plan valiations that were missing from some tests. Change-Id: I7c13b78c362aa3041643fc78af4193e687db2bf4 Signed-off-by: Douglas Viroel <viroel@gmail.com>
This commit is contained in:
@@ -66,6 +66,10 @@ class BaseInfraOptimScenarioTest(manager.ScenarioTest):
|
||||
min_microversion = None
|
||||
max_microversion = manager.LATEST_MICROVERSION
|
||||
|
||||
# Holds the initial configuration of available compute nodes, to assist
|
||||
# the rollback procedure.
|
||||
initial_compute_nodes_setup = []
|
||||
|
||||
# States where the object is waiting for some event to perform a transition
|
||||
IDLE_STATES = ('RECOMMENDED', 'FAILED', 'SUCCEEDED', 'CANCELLED')
|
||||
# States where the object can only be DELETED (end of its life-cycle)
|
||||
@@ -266,6 +270,12 @@ class BaseInfraOptimScenarioTest(manager.ScenarioTest):
|
||||
return all([ap['state'] in cls.AP_FINISHED_STATES
|
||||
for ap in action_plans['action_plans']])
|
||||
|
||||
def check_min_enabled_compute_nodes(self, min_nodes):
|
||||
enabled_compute_nodes = self.get_enabled_compute_nodes()
|
||||
msg = ("This test required at least %s enabled compute nodes, but "
|
||||
"only %s were found." % (min_nodes, len(enabled_compute_nodes)))
|
||||
self.assertGreaterEqual(len(enabled_compute_nodes), min_nodes, msg=msg)
|
||||
|
||||
def wait_for_all_action_plans_to_finish(self):
|
||||
assert test_utils.call_until_true(
|
||||
func=self._are_all_action_plans_finished,
|
||||
|
||||
@@ -45,19 +45,6 @@ class TestContinuousAudit(base.BaseInfraOptimScenarioTest):
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
# NOTE(dviroel): If the class was not skipped and we don't have at
|
||||
# least 2 compute nodes enabled, fail the test.
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
cls.fail("At least 2 enabled compute nodes are required to run "
|
||||
"continuous audit tests.")
|
||||
|
||||
@decorators.idempotent_id("bd6a18e9-bd51-4164-9e7f-4f19d9b428ba")
|
||||
@decorators.attr(type=['strategy', 'zone_migration'])
|
||||
def test_continuous_audit_zone_migration(self):
|
||||
@@ -65,7 +52,7 @@ class TestContinuousAudit(base.BaseInfraOptimScenarioTest):
|
||||
# NOTE(dviroel): We don't need to start/trigger the action plan to
|
||||
# validate continous audits, but we need to create the workload and
|
||||
# check if the strategy will get updates from the model.
|
||||
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
|
||||
src_host = self.get_enabled_compute_nodes()[0]['host']
|
||||
|
||||
@@ -29,23 +29,17 @@ class TestDataModel(base.BaseInfraOptimScenarioTest):
|
||||
min_microversion = "1.3"
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(TestDataModel, cls).resource_setup()
|
||||
def skip_checks(cls):
|
||||
super().skip_checks()
|
||||
if CONF.compute.min_compute_nodes < 1:
|
||||
raise cls.skipException(
|
||||
"Data model tests requires at least 1 compute node, "
|
||||
"skipping tests.")
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 1:
|
||||
raise cls.skipException(
|
||||
"Data model tests requires at least 1 enabled compute "
|
||||
"node, skipping tests.")
|
||||
|
||||
@decorators.idempotent_id('dabd41a4-e668-43c8-89a2-3d231e2ed79d')
|
||||
def test_data_model_with_instances(self):
|
||||
# This test requires at least one enabled compute node
|
||||
self.check_min_enabled_compute_nodes(1)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
|
||||
instances = self._create_one_instance_per_host()
|
||||
|
||||
@@ -63,22 +63,14 @@ class TestExecuteActionsViaActuator(base.BaseInfraOptimScenarioTest):
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(TestExecuteActionsViaActuator, cls).resource_setup()
|
||||
def skip_checks(cls):
|
||||
super().skip_checks()
|
||||
if CONF.compute.min_compute_nodes < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes, skipping multinode tests.")
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
def _get_flavors(self):
|
||||
return self.mgr.flavors_client.list_flavors()['flavors']
|
||||
|
||||
@@ -200,6 +192,8 @@ class TestExecuteActionsViaActuator(base.BaseInfraOptimScenarioTest):
|
||||
|
||||
@decorators.idempotent_id('0af1a181-38c8-4416-8e85-8ebca8ac1cf8')
|
||||
def test_execute_scenarios(self):
|
||||
# Migration action requires at least 2 enabled compute nodes
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
|
||||
for _, scenario in self.scenarios:
|
||||
|
||||
@@ -43,19 +43,6 @@ class TestExecuteBasicStrategy(base.BaseInfraOptimScenarioTest):
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(TestExecuteBasicStrategy, cls).resource_setup()
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
@decorators.attr(type=['strategy', 'basic'])
|
||||
@decorators.idempotent_id('62766a61-dfc4-478c-b80b-86d871227e67')
|
||||
def test_execute_basic_strategy(self):
|
||||
@@ -67,6 +54,7 @@ class TestExecuteBasicStrategy(base.BaseInfraOptimScenarioTest):
|
||||
- run the action plan
|
||||
- get results and make sure it succeeded
|
||||
"""
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
self.addCleanup(self.clean_injected_metrics)
|
||||
|
||||
@@ -44,23 +44,11 @@ class TestExecuteHostMaintenanceStrategy(base.BaseInfraOptimScenarioTest):
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
@decorators.idempotent_id('17afd352-1929-46dd-a10a-63c90bb9255d')
|
||||
@decorators.attr(type=['strategy', 'host_maintenance'])
|
||||
def test_execute_host_maintenance_strategy(self):
|
||||
# This test does not require metrics injection
|
||||
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
instances = self._create_one_instance_per_host()
|
||||
@@ -91,7 +79,7 @@ class TestExecuteHostMaintenanceStrategy(base.BaseInfraOptimScenarioTest):
|
||||
@decorators.attr(type=['strategy', 'host_maintenance'])
|
||||
def test_execute_host_maintenance_strategy_backup_node(self):
|
||||
# This test does not require metrics injection
|
||||
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
instances = self._create_one_instance_per_host()
|
||||
|
||||
@@ -43,22 +43,11 @@ class TestExecuteNodeResourceConsolidationStrategy(
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
cls.wait_for_compute_node_setup()
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
@decorators.attr(type=['strategy', 'node_resource_consolidation'])
|
||||
@decorators.idempotent_id('c0c061e9-4713-4a23-a6e1-5db794add685')
|
||||
def test_execute_node_resource_consolidation_strategy_with_auto(self):
|
||||
# This test does not require metrics injection
|
||||
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
instances = self._create_one_instance_per_host()
|
||||
@@ -77,7 +66,7 @@ class TestExecuteNodeResourceConsolidationStrategy(
|
||||
audit_template['uuid'], **audit_kwargs)
|
||||
|
||||
action_plan, _ = self.get_action_plan_and_validate_actions(
|
||||
audit['uuid'])
|
||||
audit['uuid'], ['change_nova_service_state', 'migrate'])
|
||||
|
||||
if action_plan['state'] in ('SUPERSEDED', 'SUCCEEDED'):
|
||||
# This means the action plan is superseded so we cannot trigger it,
|
||||
@@ -90,7 +79,7 @@ class TestExecuteNodeResourceConsolidationStrategy(
|
||||
@decorators.idempotent_id('12312f2b-ff7a-4722-9aa3-0262608e1ef0')
|
||||
def test_execute_node_resource_consolidation_strategy_with_specify(self):
|
||||
# This test does not require metrics injection
|
||||
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
instances = self._create_one_instance_per_host()
|
||||
@@ -109,7 +98,7 @@ class TestExecuteNodeResourceConsolidationStrategy(
|
||||
audit_template['uuid'], **audit_kwargs)
|
||||
|
||||
action_plan, _ = self.get_action_plan_and_validate_actions(
|
||||
audit['uuid'])
|
||||
audit['uuid'], ['migrate'])
|
||||
|
||||
if action_plan['state'] in ('SUPERSEDED', 'SUCCEEDED'):
|
||||
# This means the action plan is superseded so we cannot trigger it,
|
||||
|
||||
@@ -53,22 +53,11 @@ class TestRealExecuteStrategies(base.BaseInfraOptimScenarioTest):
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
cls.wait_for_compute_node_setup()
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
@decorators.attr(type=['slow', 'real_load', 'cpu'])
|
||||
@decorators.idempotent_id('672a7a4d-91a0-4753-a7a4-be28db8c1bfb')
|
||||
def test_workload_balance_strategy_cpu(self):
|
||||
# This test does not require metrics injection
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
host = self.get_enabled_compute_nodes()[0]['host']
|
||||
hypervisor = self.get_hypervisor_details(host)
|
||||
@@ -117,7 +106,7 @@ class TestRealExecuteStrategies(base.BaseInfraOptimScenarioTest):
|
||||
@decorators.idempotent_id('f1b8a0c4-2d3e-4a5b-8f7c-6d9e5f2a0b1c')
|
||||
def test_workload_balance_strategy_ram(self):
|
||||
# This test does not require metrics injection
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
host = self.get_enabled_compute_nodes()[0]['host']
|
||||
hypervisor = self.get_hypervisor_details(host)
|
||||
@@ -164,8 +153,7 @@ class TestRealExecuteStrategies(base.BaseInfraOptimScenarioTest):
|
||||
@decorators.attr(type=['slow', 'real_load'])
|
||||
def test_workload_stabilization_strategy(self):
|
||||
# This test does not require metrics injection
|
||||
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
run_command = self.COMMANDS_CREATE_LOAD['instance_cpu_usage']
|
||||
host = self.get_enabled_compute_nodes()[0]['host']
|
||||
|
||||
@@ -43,19 +43,6 @@ class TestExecuteVmWorkloadBalanceStrategy(base.BaseInfraOptimScenarioTest):
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
@decorators.attr(type=['strategy', 'vm_workload_consolidation'])
|
||||
@decorators.idempotent_id('9f3ee978-e033-4c1e-bbf2-9e5a5cb8a365')
|
||||
def test_execute_vm_workload_consolidation_strategy(self):
|
||||
@@ -68,7 +55,7 @@ class TestExecuteVmWorkloadBalanceStrategy(base.BaseInfraOptimScenarioTest):
|
||||
- get results and make sure it succeeded
|
||||
"""
|
||||
# This test requires metrics injection
|
||||
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
self.addCleanup(self.clean_injected_metrics)
|
||||
@@ -97,7 +84,7 @@ class TestExecuteVmWorkloadBalanceStrategy(base.BaseInfraOptimScenarioTest):
|
||||
audit_template['uuid'], **audit_kwargs)
|
||||
|
||||
action_plan, _ = self.get_action_plan_and_validate_actions(
|
||||
audit['uuid'])
|
||||
audit['uuid'], ['change_nova_service_state', 'migrate'])
|
||||
|
||||
if action_plan['state'] in ('SUPERSEDED', 'SUCCEEDED'):
|
||||
# This means the action plan is superseded so we cannot trigger it,
|
||||
|
||||
@@ -44,23 +44,11 @@ class TestExecuteWorkloadBalanceStrategy(base.BaseInfraOptimScenarioTest):
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
@decorators.attr(type=['strategy', 'workload_balance'])
|
||||
@decorators.idempotent_id('64a9293f-0f81-431c-afae-ecabebae53f1')
|
||||
def test_execute_workload_balance_strategy_cpu(self):
|
||||
# This test requires metrics injection
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
self.addCleanup(self.clean_injected_metrics)
|
||||
host = self.get_enabled_compute_nodes()[0]['host']
|
||||
@@ -108,7 +96,7 @@ class TestExecuteWorkloadBalanceStrategy(base.BaseInfraOptimScenarioTest):
|
||||
@decorators.idempotent_id('de4f662a-26b1-4cbe-ba8e-c213bac0a996')
|
||||
def test_execute_workload_balance_strategy_ram(self):
|
||||
# This test requires metrics injection
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
self.addCleanup(self.clean_injected_metrics)
|
||||
|
||||
|
||||
@@ -41,24 +41,11 @@ class TestExecuteWorkloadStabilizationStrategy(
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
@decorators.attr(type=['strategy', 'workload_stabilization'])
|
||||
@decorators.idempotent_id('14360d59-4923-49f7-bfe5-31d6a819b6f7')
|
||||
def test_execute_workload_stabilization_strategy_cpu(self):
|
||||
# This test requires metrics injection
|
||||
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
self.addCleanup(self.clean_injected_metrics)
|
||||
host = self.get_enabled_compute_nodes()[0]['host']
|
||||
@@ -102,8 +89,7 @@ class TestExecuteWorkloadStabilizationStrategy(
|
||||
@decorators.idempotent_id('4988b894-b237-4ebc-9af1-ecf1f9ea734e')
|
||||
def test_execute_workload_stabilization_strategy_ram(self):
|
||||
# This test requires metrics injection
|
||||
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
self.addCleanup(self.clean_injected_metrics)
|
||||
host = self.get_enabled_compute_nodes()[0]['host']
|
||||
|
||||
@@ -43,18 +43,6 @@ class TestZoneMigrationStrategyBase(base.BaseInfraOptimScenarioTest):
|
||||
if not CONF.compute_feature_enabled.live_migration:
|
||||
raise cls.skipException("Live migration is not enabled")
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
|
||||
enabled_compute_nodes = cls.get_enabled_compute_nodes()
|
||||
cls.wait_for_compute_node_setup()
|
||||
|
||||
if len(enabled_compute_nodes) < 2:
|
||||
raise cls.skipException(
|
||||
"Less than 2 compute nodes are enabled, "
|
||||
"skipping multinode tests.")
|
||||
|
||||
|
||||
class TestExecuteZoneMigrationStrategy(TestZoneMigrationStrategyBase):
|
||||
"""Tests for action plans"""
|
||||
@@ -63,8 +51,7 @@ class TestExecuteZoneMigrationStrategy(TestZoneMigrationStrategyBase):
|
||||
@decorators.attr(type=['strategy', 'zone_migration'])
|
||||
def test_execute_zone_migration_with_destination_host(self):
|
||||
# This test requires metrics injection
|
||||
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
instances = self._create_one_instance_per_host()
|
||||
# wait for compute model updates
|
||||
@@ -96,8 +83,7 @@ class TestExecuteZoneMigrationStrategy(TestZoneMigrationStrategyBase):
|
||||
@decorators.attr(type=['strategy', 'zone_migration'])
|
||||
def test_execute_zone_migration_without_destination_host(self):
|
||||
# This test requires metrics injection
|
||||
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.check_min_enabled_compute_nodes(2)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
instances = self._create_one_instance_per_host()
|
||||
# wait for compute model updates
|
||||
@@ -152,7 +138,6 @@ class TestExecuteZoneMigrationStrategyVolume(TestZoneMigrationStrategyBase):
|
||||
@decorators.attr(type=['strategy', 'zone_migration', 'volume_migration'])
|
||||
@decorators.idempotent_id('f8f4d551-d892-4111-ab92-5b6b5523e5dc')
|
||||
def test_execute_zone_migration_volume_retype(self):
|
||||
self.addCleanup(self.rollback_compute_nodes_status)
|
||||
self.addCleanup(self.wait_delete_instances_from_model)
|
||||
|
||||
# create second volume type
|
||||
|
||||
Reference in New Issue
Block a user