Port to the tempest stable plugin interface (clients)
This is one of the last tempest plugins which was still not using the proper interface to define its clients. (Hopefully) no behavioral changes, just refactoring. Change-Id: Ia57c771186cd1bf283f30b58007395d33aefa4a9
This commit is contained in:
parent
645067abfe
commit
545a8875d0
@ -20,18 +20,11 @@ from tempest.lib.common.utils import data_utils
|
|||||||
from tempest.lib import decorators
|
from tempest.lib import decorators
|
||||||
|
|
||||||
from cinder_tempest_plugin.api.volume import base
|
from cinder_tempest_plugin.api.volume import base
|
||||||
from cinder_tempest_plugin import cinder_clients
|
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
||||||
@classmethod
|
|
||||||
def setup_clients(cls):
|
|
||||||
super(ConsistencyGroupsV2Test, cls).setup_clients()
|
|
||||||
|
|
||||||
manager = cinder_clients.Manager(cls.os_admin)
|
|
||||||
cls.consistencygroups_adm_client = manager.consistencygroups_adm_client
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def skip_checks(cls):
|
def skip_checks(cls):
|
||||||
@ -41,16 +34,16 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
"feature disabled")
|
"feature disabled")
|
||||||
|
|
||||||
def _delete_consistencygroup(self, cg_id):
|
def _delete_consistencygroup(self, cg_id):
|
||||||
self.consistencygroups_adm_client.delete_consistencygroup(cg_id)
|
self.admin_consistencygroups_client.delete_consistencygroup(cg_id)
|
||||||
vols = self.admin_volume_client.list_volumes(detail=True)['volumes']
|
vols = self.admin_volume_client.list_volumes(detail=True)['volumes']
|
||||||
for vol in vols:
|
for vol in vols:
|
||||||
if vol['consistencygroup_id'] == cg_id:
|
if vol['consistencygroup_id'] == cg_id:
|
||||||
self.admin_volume_client.wait_for_resource_deletion(vol['id'])
|
self.admin_volume_client.wait_for_resource_deletion(vol['id'])
|
||||||
self.consistencygroups_adm_client.wait_for_consistencygroup_deletion(
|
self.admin_consistencygroups_client.wait_for_consistencygroup_deletion(
|
||||||
cg_id)
|
cg_id)
|
||||||
|
|
||||||
def _delete_cgsnapshot(self, cgsnapshot_id, cg_id):
|
def _delete_cgsnapshot(self, cgsnapshot_id, cg_id):
|
||||||
self.consistencygroups_adm_client.delete_cgsnapshot(cgsnapshot_id)
|
self.admin_consistencygroups_client.delete_cgsnapshot(cgsnapshot_id)
|
||||||
vols = self.admin_volume_client.list_volumes(detail=True)['volumes']
|
vols = self.admin_volume_client.list_volumes(detail=True)['volumes']
|
||||||
snapshots = self.os_admin.snapshots_v2_client.list_snapshots(
|
snapshots = self.os_admin.snapshots_v2_client.list_snapshots(
|
||||||
detail=True)['snapshots']
|
detail=True)['snapshots']
|
||||||
@ -60,7 +53,7 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
vol['id'] == snap['volume_id']):
|
vol['id'] == snap['volume_id']):
|
||||||
(self.snapshots_client.
|
(self.snapshots_client.
|
||||||
wait_for_resource_deletion(snap['id']))
|
wait_for_resource_deletion(snap['id']))
|
||||||
self.consistencygroups_adm_client.wait_for_cgsnapshot_deletion(
|
self.admin_consistencygroups_client.wait_for_cgsnapshot_deletion(
|
||||||
cgsnapshot_id)
|
cgsnapshot_id)
|
||||||
|
|
||||||
@decorators.idempotent_id('3fe776ba-ec1f-4e6c-8d78-4b14c3a7fc44')
|
@decorators.idempotent_id('3fe776ba-ec1f-4e6c-8d78-4b14c3a7fc44')
|
||||||
@ -73,10 +66,10 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create CG
|
# Create CG
|
||||||
cg_name = data_utils.rand_name('CG')
|
cg_name = data_utils.rand_name('CG')
|
||||||
create_consistencygroup = (
|
create_consistencygroup = (
|
||||||
self.consistencygroups_adm_client.create_consistencygroup)
|
self.admin_consistencygroups_client.create_consistencygroup)
|
||||||
cg = create_consistencygroup(volume_type['id'],
|
cg = create_consistencygroup(volume_type['id'],
|
||||||
name=cg_name)['consistencygroup']
|
name=cg_name)['consistencygroup']
|
||||||
self.consistencygroups_adm_client.wait_for_consistencygroup_status(
|
self.admin_consistencygroups_client.wait_for_consistencygroup_status(
|
||||||
cg['id'], 'available')
|
cg['id'], 'available')
|
||||||
self.assertEqual(cg_name, cg['name'])
|
self.assertEqual(cg_name, cg['name'])
|
||||||
|
|
||||||
@ -92,12 +85,12 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
volume['id'], 'available')
|
volume['id'], 'available')
|
||||||
|
|
||||||
# Get a given CG
|
# Get a given CG
|
||||||
cg = self.consistencygroups_adm_client.show_consistencygroup(
|
cg = self.admin_consistencygroups_client.show_consistencygroup(
|
||||||
cg['id'])['consistencygroup']
|
cg['id'])['consistencygroup']
|
||||||
self.assertEqual(cg_name, cg['name'])
|
self.assertEqual(cg_name, cg['name'])
|
||||||
|
|
||||||
# Get all CGs with detail
|
# Get all CGs with detail
|
||||||
cgs = self.consistencygroups_adm_client.list_consistencygroups(
|
cgs = self.admin_consistencygroups_client.list_consistencygroups(
|
||||||
detail=True)['consistencygroups']
|
detail=True)['consistencygroups']
|
||||||
self.assertIn((cg['name'], cg['id']),
|
self.assertIn((cg['name'], cg['id']),
|
||||||
[(m['name'], m['id']) for m in cgs])
|
[(m['name'], m['id']) for m in cgs])
|
||||||
@ -117,10 +110,10 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create CG
|
# Create CG
|
||||||
cg_name = data_utils.rand_name('CG')
|
cg_name = data_utils.rand_name('CG')
|
||||||
create_consistencygroup = (
|
create_consistencygroup = (
|
||||||
self.consistencygroups_adm_client.create_consistencygroup)
|
self.admin_consistencygroups_client.create_consistencygroup)
|
||||||
cg = create_consistencygroup(volume_type['id'],
|
cg = create_consistencygroup(volume_type['id'],
|
||||||
name=cg_name)['consistencygroup']
|
name=cg_name)['consistencygroup']
|
||||||
self.consistencygroups_adm_client.wait_for_consistencygroup_status(
|
self.admin_consistencygroups_client.wait_for_consistencygroup_status(
|
||||||
cg['id'], 'available')
|
cg['id'], 'available')
|
||||||
self.assertEqual(cg_name, cg['name'])
|
self.assertEqual(cg_name, cg['name'])
|
||||||
|
|
||||||
@ -137,10 +130,10 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create cgsnapshot
|
# Create cgsnapshot
|
||||||
cgsnapshot_name = data_utils.rand_name('cgsnapshot')
|
cgsnapshot_name = data_utils.rand_name('cgsnapshot')
|
||||||
create_cgsnapshot = (
|
create_cgsnapshot = (
|
||||||
self.consistencygroups_adm_client.create_cgsnapshot)
|
self.admin_consistencygroups_client.create_cgsnapshot)
|
||||||
cgsnapshot = create_cgsnapshot(cg['id'],
|
cgsnapshot = create_cgsnapshot(cg['id'],
|
||||||
name=cgsnapshot_name)['cgsnapshot']
|
name=cgsnapshot_name)['cgsnapshot']
|
||||||
self.consistencygroups_adm_client.wait_for_cgsnapshot_status(
|
self.admin_consistencygroups_client.wait_for_cgsnapshot_status(
|
||||||
cgsnapshot['id'], 'available')
|
cgsnapshot['id'], 'available')
|
||||||
self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
|
self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
|
||||||
snapshots = self.os_admin.snapshots_v2_client.list_snapshots(
|
snapshots = self.os_admin.snapshots_v2_client.list_snapshots(
|
||||||
@ -152,12 +145,12 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
snap['id'], 'available')
|
snap['id'], 'available')
|
||||||
|
|
||||||
# Get a given CG snapshot
|
# Get a given CG snapshot
|
||||||
cgsnapshot = self.consistencygroups_adm_client.show_cgsnapshot(
|
cgsnapshot = self.admin_consistencygroups_client.show_cgsnapshot(
|
||||||
cgsnapshot['id'])['cgsnapshot']
|
cgsnapshot['id'])['cgsnapshot']
|
||||||
self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
|
self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
|
||||||
|
|
||||||
# Get all CG snapshots with detail
|
# Get all CG snapshots with detail
|
||||||
cgsnapshots = self.consistencygroups_adm_client.list_cgsnapshots(
|
cgsnapshots = self.admin_consistencygroups_client.list_cgsnapshots(
|
||||||
detail=True)['cgsnapshots']
|
detail=True)['cgsnapshots']
|
||||||
self.assertIn((cgsnapshot['name'], cgsnapshot['id']),
|
self.assertIn((cgsnapshot['name'], cgsnapshot['id']),
|
||||||
[(m['name'], m['id']) for m in cgsnapshots])
|
[(m['name'], m['id']) for m in cgsnapshots])
|
||||||
@ -177,10 +170,10 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create CG
|
# Create CG
|
||||||
cg_name = data_utils.rand_name('CG')
|
cg_name = data_utils.rand_name('CG')
|
||||||
create_consistencygroup = (
|
create_consistencygroup = (
|
||||||
self.consistencygroups_adm_client.create_consistencygroup)
|
self.admin_consistencygroups_client.create_consistencygroup)
|
||||||
cg = create_consistencygroup(volume_type['id'],
|
cg = create_consistencygroup(volume_type['id'],
|
||||||
name=cg_name)['consistencygroup']
|
name=cg_name)['consistencygroup']
|
||||||
self.consistencygroups_adm_client.wait_for_consistencygroup_status(
|
self.admin_consistencygroups_client.wait_for_consistencygroup_status(
|
||||||
cg['id'], 'available')
|
cg['id'], 'available')
|
||||||
self.assertEqual(cg_name, cg['name'])
|
self.assertEqual(cg_name, cg['name'])
|
||||||
|
|
||||||
@ -197,10 +190,10 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create cgsnapshot
|
# Create cgsnapshot
|
||||||
cgsnapshot_name = data_utils.rand_name('cgsnapshot')
|
cgsnapshot_name = data_utils.rand_name('cgsnapshot')
|
||||||
create_cgsnapshot = (
|
create_cgsnapshot = (
|
||||||
self.consistencygroups_adm_client.create_cgsnapshot)
|
self.admin_consistencygroups_client.create_cgsnapshot)
|
||||||
cgsnapshot = create_cgsnapshot(cg['id'],
|
cgsnapshot = create_cgsnapshot(cg['id'],
|
||||||
name=cgsnapshot_name)['cgsnapshot']
|
name=cgsnapshot_name)['cgsnapshot']
|
||||||
self.consistencygroups_adm_client.wait_for_cgsnapshot_status(
|
self.admin_consistencygroups_client.wait_for_cgsnapshot_status(
|
||||||
cgsnapshot['id'], 'available')
|
cgsnapshot['id'], 'available')
|
||||||
self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
|
self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
|
||||||
snapshots = self.snapshots_client.list_snapshots(
|
snapshots = self.snapshots_client.list_snapshots(
|
||||||
@ -213,10 +206,12 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create CG from CG snapshot
|
# Create CG from CG snapshot
|
||||||
cg_name2 = data_utils.rand_name('CG_from_snap')
|
cg_name2 = data_utils.rand_name('CG_from_snap')
|
||||||
create_consistencygroup2 = (
|
create_consistencygroup2 = (
|
||||||
self.consistencygroups_adm_client.create_consistencygroup_from_src)
|
self.admin_consistencygroups_client.
|
||||||
|
create_consistencygroup_from_src
|
||||||
|
)
|
||||||
cg2 = create_consistencygroup2(cgsnapshot_id=cgsnapshot['id'],
|
cg2 = create_consistencygroup2(cgsnapshot_id=cgsnapshot['id'],
|
||||||
name=cg_name2)['consistencygroup']
|
name=cg_name2)['consistencygroup']
|
||||||
self.consistencygroups_adm_client.wait_for_consistencygroup_status(
|
self.admin_consistencygroups_client.wait_for_consistencygroup_status(
|
||||||
cg2['id'], 'available')
|
cg2['id'], 'available')
|
||||||
self.assertEqual(cg_name2, cg2['name'])
|
self.assertEqual(cg_name2, cg2['name'])
|
||||||
vols = self.admin_volume_client.list_volumes(
|
vols = self.admin_volume_client.list_volumes(
|
||||||
@ -242,10 +237,10 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create CG
|
# Create CG
|
||||||
cg_name = data_utils.rand_name('CG')
|
cg_name = data_utils.rand_name('CG')
|
||||||
create_consistencygroup = (
|
create_consistencygroup = (
|
||||||
self.consistencygroups_adm_client.create_consistencygroup)
|
self.admin_consistencygroups_client.create_consistencygroup)
|
||||||
cg = create_consistencygroup(volume_type['id'],
|
cg = create_consistencygroup(volume_type['id'],
|
||||||
name=cg_name)['consistencygroup']
|
name=cg_name)['consistencygroup']
|
||||||
self.consistencygroups_adm_client.wait_for_consistencygroup_status(
|
self.admin_consistencygroups_client.wait_for_consistencygroup_status(
|
||||||
cg['id'], 'available')
|
cg['id'], 'available')
|
||||||
self.assertEqual(cg_name, cg['name'])
|
self.assertEqual(cg_name, cg['name'])
|
||||||
|
|
||||||
@ -262,10 +257,12 @@ class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
|
|||||||
# Create CG from CG
|
# Create CG from CG
|
||||||
cg_name2 = data_utils.rand_name('CG_from_cg')
|
cg_name2 = data_utils.rand_name('CG_from_cg')
|
||||||
create_consistencygroup2 = (
|
create_consistencygroup2 = (
|
||||||
self.consistencygroups_adm_client.create_consistencygroup_from_src)
|
self.admin_consistencygroups_client.
|
||||||
|
create_consistencygroup_from_src
|
||||||
|
)
|
||||||
cg2 = create_consistencygroup2(source_cgid=cg['id'],
|
cg2 = create_consistencygroup2(source_cgid=cg['id'],
|
||||||
name=cg_name2)['consistencygroup']
|
name=cg_name2)['consistencygroup']
|
||||||
self.consistencygroups_adm_client.wait_for_consistencygroup_status(
|
self.admin_consistencygroups_client.wait_for_consistencygroup_status(
|
||||||
cg2['id'], 'available')
|
cg2['id'], 'available')
|
||||||
self.assertEqual(cg_name2, cg2['name'])
|
self.assertEqual(cg_name2, cg2['name'])
|
||||||
vols = self.admin_volume_client.list_volumes(
|
vols = self.admin_volume_client.list_volumes(
|
||||||
|
@ -50,6 +50,9 @@ class BaseVolumeTest(api_version_utils.BaseMicroversionTest,
|
|||||||
cls.backups_client = cls.os_primary.backups_client_latest
|
cls.backups_client = cls.os_primary.backups_client_latest
|
||||||
cls.volumes_client = cls.os_primary.volumes_client_latest
|
cls.volumes_client = cls.os_primary.volumes_client_latest
|
||||||
cls.snapshots_client = cls.os_primary.snapshots_client_latest
|
cls.snapshots_client = cls.os_primary.snapshots_client_latest
|
||||||
|
cls.volume_revert_client = (
|
||||||
|
cls.os_primary.volume_revert_v3.VolumeRevertClient()
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup_credentials(cls):
|
def setup_credentials(cls):
|
||||||
@ -196,6 +199,9 @@ class BaseVolumeAdminTest(BaseVolumeTest):
|
|||||||
cls.admin_volume_types_client = cls.os_admin.volume_types_client_latest
|
cls.admin_volume_types_client = cls.os_admin.volume_types_client_latest
|
||||||
cls.admin_backups_client = cls.os_admin.backups_client_latest
|
cls.admin_backups_client = cls.os_admin.backups_client_latest
|
||||||
cls.admin_volume_client = cls.os_admin.volumes_client_latest
|
cls.admin_volume_client = cls.os_admin.volumes_client_latest
|
||||||
|
cls.admin_consistencygroups_client = (
|
||||||
|
cls.os_admin.consistencygroups_v3.ConsistencyGroupsClient()
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_volume_type(cls, name=None, **kwargs):
|
def create_volume_type(cls, name=None, **kwargs):
|
||||||
|
@ -19,7 +19,6 @@ from tempest.lib import decorators
|
|||||||
from tempest.lib import exceptions
|
from tempest.lib import exceptions
|
||||||
|
|
||||||
from cinder_tempest_plugin.api.volume import base
|
from cinder_tempest_plugin.api.volume import base
|
||||||
from cinder_tempest_plugin import cinder_clients
|
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
@ -33,13 +32,6 @@ class VolumeRevertTests(base.BaseVolumeTest):
|
|||||||
if not CONF.volume_feature_enabled.volume_revert:
|
if not CONF.volume_feature_enabled.volume_revert:
|
||||||
raise cls.skipException("Cinder volume revert feature disabled")
|
raise cls.skipException("Cinder volume revert feature disabled")
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup_clients(cls):
|
|
||||||
super(VolumeRevertTests, cls).setup_clients()
|
|
||||||
|
|
||||||
manager = cinder_clients.Manager(cls.os_primary)
|
|
||||||
cls.volume_revert_client = manager.volume_revert_client
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(VolumeRevertTests, self).setUp()
|
super(VolumeRevertTests, self).setUp()
|
||||||
# Create volume
|
# Create volume
|
||||||
|
@ -14,27 +14,19 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from tempest import config
|
from tempest import config
|
||||||
|
from tempest.lib.services import clients
|
||||||
from cinder_tempest_plugin.services import consistencygroups_client
|
|
||||||
from cinder_tempest_plugin.services import volume_revert_client
|
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
class Manager(object):
|
class Clients(clients.ServiceClients):
|
||||||
def __init__(self, base_manager):
|
"""Tempest stable service clients and loaded plugins service clients"""
|
||||||
params = {
|
|
||||||
'service': CONF.volume.catalog_type,
|
|
||||||
'region': CONF.volume.region or CONF.identity.region,
|
|
||||||
'endpoint_type': CONF.volume.endpoint_type,
|
|
||||||
'build_interval': CONF.volume.build_interval,
|
|
||||||
'build_timeout': CONF.volume.build_timeout
|
|
||||||
}
|
|
||||||
params.update(base_manager.default_params)
|
|
||||||
auth_provider = base_manager.auth_provider
|
|
||||||
|
|
||||||
self.consistencygroups_adm_client = (
|
def __init__(self, credentials, service=None):
|
||||||
consistencygroups_client.ConsistencyGroupsClient(auth_provider,
|
"""Emulate the interface of Tempest's clients.Manager"""
|
||||||
**params))
|
# Identity settings
|
||||||
self.volume_revert_client = (
|
if CONF.identity.auth_version == 'v2':
|
||||||
volume_revert_client.VolumeRevertClient(auth_provider, **params))
|
identity_uri = CONF.identity.uri
|
||||||
|
else:
|
||||||
|
identity_uri = CONF.identity.uri_v3
|
||||||
|
super(Clients, self).__init__(credentials, identity_uri)
|
||||||
|
@ -69,3 +69,26 @@ class CinderTempestPlugin(plugins.TempestPlugin):
|
|||||||
project_config.barbican_service_option))
|
project_config.barbican_service_option))
|
||||||
|
|
||||||
return opt_lists
|
return opt_lists
|
||||||
|
|
||||||
|
def get_service_clients(self):
|
||||||
|
volumes_config = config.service_client_config('volume')
|
||||||
|
|
||||||
|
consistencygroups_params = {
|
||||||
|
'name': 'consistencygroups_v3',
|
||||||
|
'service_version': 'consistencygroups.v3',
|
||||||
|
'module_path': 'cinder_tempest_plugin.services.'
|
||||||
|
'consistencygroups_client',
|
||||||
|
'client_names': ['ConsistencyGroupsClient'],
|
||||||
|
}
|
||||||
|
consistencygroups_params.update(volumes_config)
|
||||||
|
|
||||||
|
volumerevert_params = {
|
||||||
|
'name': 'volume_revert_v3',
|
||||||
|
'service_version': 'volume_revert.v3',
|
||||||
|
'module_path': 'cinder_tempest_plugin.services.'
|
||||||
|
'volume_revert_client',
|
||||||
|
'client_names': ['VolumeRevertClient'],
|
||||||
|
}
|
||||||
|
volumerevert_params.update(volumes_config)
|
||||||
|
|
||||||
|
return [consistencygroups_params, volumerevert_params]
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
#
|
||||||
|
# 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 cinder_tempest_plugin.services.consistencygroups_client import \
|
||||||
|
ConsistencyGroupsClient
|
||||||
|
from cinder_tempest_plugin.services.volume_revert_client import \
|
||||||
|
VolumeRevertClient
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'ConsistencyGroupsClient',
|
||||||
|
'VolumeRevertClient'
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user