Get rid of RequestContext.tenant_id
This additional attribute can be replaced by the built-in project_id attribute. Switch to the built-in one to reduce implementations specifically maintained in the heat repo. Change-Id: I21eda816f8f78e63f1d6b9afae9f0634d026f2c3
This commit is contained in:
parent
0adfd85b1d
commit
6923c6a155
@ -85,7 +85,7 @@ class SoftwareConfigController(object):
|
||||
req.params.get(name))
|
||||
|
||||
if global_tenant:
|
||||
return self.global_index(req, req.context.tenant_id)
|
||||
return self.global_index(req, req.context.project_id)
|
||||
|
||||
return self._index(req)
|
||||
|
||||
|
@ -360,7 +360,7 @@ class StackController(object):
|
||||
req.params.get(name))
|
||||
|
||||
if global_tenant:
|
||||
return self.global_index(req, req.context.tenant_id)
|
||||
return self.global_index(req, req.context.project_id)
|
||||
|
||||
return self._index(req)
|
||||
|
||||
@ -516,7 +516,7 @@ class StackController(object):
|
||||
Add the flag patch to the args so the engine code can distinguish
|
||||
"""
|
||||
data = InstantiationData(body, patch=True)
|
||||
_target = {"project_id": req.context.tenant_id}
|
||||
_target = {"project_id": req.context.project_id}
|
||||
|
||||
policy_act = 'update_no_change' if data.no_change() else 'update_patch'
|
||||
allowed = req.context.policy.enforce(
|
||||
|
@ -35,9 +35,9 @@ def registered_policy_enforce(handler):
|
||||
# bypass project_id check, because admin should have access to all
|
||||
# projects.
|
||||
if req.context.is_admin and req.context.project_id:
|
||||
tenant_id = req.context.tenant_id
|
||||
tenant_id = req.context.project_id
|
||||
_target = {"project_id": tenant_id}
|
||||
if req.context.tenant_id != tenant_id:
|
||||
if req.context.project_id != tenant_id:
|
||||
raise exc.HTTPForbidden()
|
||||
allowed = req.context.policy.enforce(
|
||||
context=req.context,
|
||||
@ -61,7 +61,7 @@ def no_policy_enforce(handler):
|
||||
"""
|
||||
@functools.wraps(handler)
|
||||
def handle_stack_method(controller, req, tenant_id, **kwargs):
|
||||
if req.context.tenant_id != tenant_id and not req.context.is_admin:
|
||||
if req.context.project_id != tenant_id and not req.context.is_admin:
|
||||
raise exc.HTTPForbidden()
|
||||
return handler(controller, req, **kwargs)
|
||||
|
||||
@ -80,7 +80,7 @@ def registered_identified_stack(handler):
|
||||
def _identified_stack(handler):
|
||||
@functools.wraps(handler)
|
||||
def handle_stack_method(controller, req, stack_name, stack_id, **kwargs):
|
||||
stack_identity = identifier.HeatIdentifier(req.context.tenant_id,
|
||||
stack_identity = identifier.HeatIdentifier(req.context.project_id,
|
||||
stack_name,
|
||||
stack_id)
|
||||
return handler(controller, req, dict(stack_identity), **kwargs)
|
||||
|
@ -59,17 +59,6 @@ def list_opts():
|
||||
yield TRUSTEE_CONF_GROUP, trustee_opts
|
||||
|
||||
|
||||
def _moved_attr(new_name):
|
||||
|
||||
def getter(self):
|
||||
return getattr(self, new_name)
|
||||
|
||||
def setter(self, value):
|
||||
setattr(self, new_name, value)
|
||||
|
||||
return property(getter, setter)
|
||||
|
||||
|
||||
@enginefacade.transaction_context_provider
|
||||
class RequestContext(context.RequestContext):
|
||||
"""Stores information about the security context.
|
||||
@ -124,8 +113,6 @@ class RequestContext(context.RequestContext):
|
||||
self._object_cache[cache_cls] = cache
|
||||
return cache
|
||||
|
||||
tenant_id = _moved_attr('project_id')
|
||||
|
||||
@property
|
||||
def keystone_session(self):
|
||||
if not self._keystone_session.auth:
|
||||
|
@ -374,7 +374,7 @@ def _resource_get_all_by_physical_resource_id(context, physical_resource_id):
|
||||
).all()
|
||||
|
||||
for result in results:
|
||||
if context is None or context.is_admin or context.tenant_id in (
|
||||
if context is None or context.is_admin or context.project_id in (
|
||||
result.stack.tenant, result.stack.stack_user_project_id,
|
||||
):
|
||||
yield result
|
||||
@ -646,8 +646,8 @@ def stack_get_by_name_and_owner_id(context, stack_name, owner_id):
|
||||
orm.joinedload(models.Stack.raw_template),
|
||||
).filter(
|
||||
sqlalchemy.or_(
|
||||
models.Stack.tenant == context.tenant_id,
|
||||
models.Stack.stack_user_project_id == context.tenant_id,
|
||||
models.Stack.tenant == context.project_id,
|
||||
models.Stack.stack_user_project_id == context.project_id,
|
||||
)
|
||||
).filter_by(name=stack_name).filter_by(owner_id=owner_id)
|
||||
return query.first()
|
||||
@ -665,8 +665,8 @@ def _stack_get_by_name(context, stack_name):
|
||||
orm.joinedload(models.Stack.raw_template),
|
||||
).filter(
|
||||
sqlalchemy.or_(
|
||||
models.Stack.tenant == context.tenant_id,
|
||||
models.Stack.stack_user_project_id == context.tenant_id),
|
||||
models.Stack.tenant == context.project_id,
|
||||
models.Stack.stack_user_project_id == context.project_id),
|
||||
).filter_by(name=stack_name)
|
||||
return query.order_by(models.Stack.created_at).first()
|
||||
|
||||
@ -692,8 +692,8 @@ def _stack_get(context, stack_id, show_deleted=False, eager_load=True):
|
||||
# stacks in the stack_user_project_id (in the heat stack user domain)
|
||||
if (result is not None
|
||||
and context is not None and not context.is_admin
|
||||
and context.tenant_id not in (result.tenant,
|
||||
result.stack_user_project_id)):
|
||||
and context.project_id not in (result.tenant,
|
||||
result.stack_user_project_id)):
|
||||
return None
|
||||
return result
|
||||
|
||||
@ -792,7 +792,7 @@ def _query_stack_get_all(context, show_deleted=False,
|
||||
).filter_by(owner_id=None)
|
||||
|
||||
if not context.is_admin:
|
||||
query = query.filter_by(tenant=context.tenant_id)
|
||||
query = query.filter_by(tenant=context.project_id)
|
||||
|
||||
query = query.options(orm.subqueryload(models.Stack.tags))
|
||||
if tags:
|
||||
@ -907,8 +907,8 @@ def stack_update(context, stack_id, values, exp_trvsl=None):
|
||||
(models.Stack.deleted_at.is_(None))))
|
||||
if not context.is_admin:
|
||||
query = query.filter(sqlalchemy.or_(
|
||||
models.Stack.tenant == context.tenant_id,
|
||||
models.Stack.stack_user_project_id == context.tenant_id))
|
||||
models.Stack.tenant == context.project_id,
|
||||
models.Stack.stack_user_project_id == context.project_id))
|
||||
if exp_trvsl is not None:
|
||||
query = query.filter(models.Stack.current_traversal == exp_trvsl)
|
||||
rows_updated = query.update(values, synchronize_session=False)
|
||||
@ -1188,7 +1188,7 @@ def event_get_all_by_tenant(context, limit=None, marker=None,
|
||||
query = db_filters.exact_filter(query, models.Event, filters)
|
||||
query = query.join(
|
||||
models.Event.stack
|
||||
).filter_by(tenant=context.tenant_id).filter_by(deleted_at=None)
|
||||
).filter_by(tenant=context.project_id).filter_by(deleted_at=None)
|
||||
filters = None
|
||||
return _events_filter_and_page_query(context, query, limit, marker,
|
||||
sort_keys, sort_dir, filters).all()
|
||||
@ -1302,8 +1302,8 @@ def _all_backup_stack_ids(context, stack_id):
|
||||
yield backup_id
|
||||
else:
|
||||
q_backup = context.session.query(models.Stack).filter(sqlalchemy.or_(
|
||||
models.Stack.tenant == context.tenant_id,
|
||||
models.Stack.stack_user_project_id == context.tenant_id))
|
||||
models.Stack.tenant == context.project_id,
|
||||
models.Stack.stack_user_project_id == context.project_id))
|
||||
q_backup = q_backup.filter_by(name=stack.name + '*')
|
||||
q_backup = q_backup.filter_by(owner_id=stack_id)
|
||||
for backup in q_backup.all():
|
||||
@ -1413,7 +1413,7 @@ def software_config_get(context, config_id):
|
||||
def _software_config_get(context, config_id):
|
||||
result = context.session.get(models.SoftwareConfig, config_id)
|
||||
if (result is not None and context is not None and not context.is_admin and
|
||||
result.tenant != context.tenant_id):
|
||||
result.tenant != context.project_id):
|
||||
result = None
|
||||
|
||||
if not result:
|
||||
@ -1426,7 +1426,7 @@ def _software_config_get(context, config_id):
|
||||
def software_config_get_all(context, limit=None, marker=None):
|
||||
query = context.session.query(models.SoftwareConfig)
|
||||
if not context.is_admin:
|
||||
query = query.filter_by(tenant=context.tenant_id)
|
||||
query = query.filter_by(tenant=context.project_id)
|
||||
return _paginate_query(context, query, models.SoftwareConfig,
|
||||
limit=limit, marker=marker).all()
|
||||
|
||||
@ -1435,7 +1435,7 @@ def software_config_get_all(context, limit=None, marker=None):
|
||||
def software_config_count_all(context):
|
||||
query = context.session.query(models.SoftwareConfig)
|
||||
if not context.is_admin:
|
||||
query = query.filter_by(tenant=context.tenant_id)
|
||||
query = query.filter_by(tenant=context.project_id)
|
||||
return query.count()
|
||||
|
||||
|
||||
@ -1485,8 +1485,8 @@ def _software_deployment_get(context, deployment_id):
|
||||
orm.joinedload(models.SoftwareDeployment.config),
|
||||
).first()
|
||||
if (result is not None and context is not None and not context.is_admin and
|
||||
context.tenant_id not in (result.tenant,
|
||||
result.stack_user_project_id)):
|
||||
context.project_id not in (result.tenant,
|
||||
result.stack_user_project_id)):
|
||||
result = None
|
||||
|
||||
if not result:
|
||||
@ -1502,8 +1502,8 @@ def software_deployment_get_all(context, server_id=None):
|
||||
if not context.is_admin:
|
||||
query = query.filter(
|
||||
sqlalchemy.or_(
|
||||
sd.tenant == context.tenant_id,
|
||||
sd.stack_user_project_id == context.tenant_id,
|
||||
sd.tenant == context.project_id,
|
||||
sd.stack_user_project_id == context.project_id,
|
||||
)
|
||||
)
|
||||
if server_id:
|
||||
@ -1525,8 +1525,8 @@ def software_deployment_count_all(context):
|
||||
if not context.is_admin:
|
||||
query = query.filter(
|
||||
sqlalchemy.or_(
|
||||
sd.tenant == context.tenant_id,
|
||||
sd.stack_user_project_id == context.tenant_id,
|
||||
sd.tenant == context.project_id,
|
||||
sd.stack_user_project_id == context.project_id,
|
||||
)
|
||||
)
|
||||
|
||||
@ -1571,7 +1571,7 @@ def snapshot_get(context, snapshot_id):
|
||||
def _snapshot_get(context, snapshot_id):
|
||||
result = context.session.get(models.Snapshot, snapshot_id)
|
||||
if (result is not None and context is not None and
|
||||
context.tenant_id != result.tenant):
|
||||
context.project_id != result.tenant):
|
||||
result = None
|
||||
|
||||
if not result:
|
||||
@ -1607,13 +1607,13 @@ def snapshot_delete(context, snapshot_id):
|
||||
@context_manager.reader
|
||||
def snapshot_get_all_by_stack(context, stack_id):
|
||||
return context.session.query(models.Snapshot).filter_by(
|
||||
stack_id=stack_id, tenant=context.tenant_id)
|
||||
stack_id=stack_id, tenant=context.project_id)
|
||||
|
||||
|
||||
@context_manager.reader
|
||||
def snapshot_count_all_by_stack(context, stack_id):
|
||||
return context.session.query(models.Snapshot).filter_by(
|
||||
stack_id=stack_id, tenant=context.tenant_id).count()
|
||||
stack_id=stack_id, tenant=context.project_id).count()
|
||||
|
||||
|
||||
# service
|
||||
|
@ -411,7 +411,7 @@ def format_notification_body(stack):
|
||||
|
||||
updated_at = heat_timeutils.isotime(stack.updated_time)
|
||||
result = {
|
||||
rpc_api.NOTIFY_TENANT_ID: stack.context.tenant_id,
|
||||
rpc_api.NOTIFY_TENANT_ID: stack.context.project_id,
|
||||
rpc_api.NOTIFY_USER_ID: stack.context.username,
|
||||
# deprecated: please use rpc_api.NOTIFY_USERID for user id or
|
||||
# rpc_api.NOTIFY_USERNAME for user name.
|
||||
|
@ -80,7 +80,7 @@ class GlanceClientPlugin(client_plugin.ClientPlugin):
|
||||
:param image_identifier: image name or a UUID-like identifier
|
||||
:returns: the id of the requested :image_identifier:
|
||||
"""
|
||||
return self._find_image_id(self.context.tenant_id,
|
||||
return self._find_image_id(self.context.project_id,
|
||||
image_identifier)
|
||||
|
||||
@os_client.MEMOIZE_FINDER
|
||||
|
@ -55,7 +55,7 @@ class HeatClientPlugin(client_plugin.ClientPlugin):
|
||||
def get_heat_url(self):
|
||||
heat_url = self._get_client_option(CLIENT_NAME, 'url')
|
||||
if heat_url:
|
||||
tenant_id = self.context.tenant_id
|
||||
tenant_id = self.context.project_id
|
||||
heat_url = heat_url % {'tenant_id': tenant_id}
|
||||
else:
|
||||
endpoint_type = self._get_client_option(CLIENT_NAME,
|
||||
|
@ -303,12 +303,12 @@ class KsClientWrapper(object):
|
||||
# Create the user
|
||||
user = self.client.users.create(
|
||||
name=self._get_username(username), password=password,
|
||||
default_project=self.context.tenant_id)
|
||||
default_project=self.context.project_id)
|
||||
# Add user to heat_stack_user_role
|
||||
LOG.debug("Adding user %(user)s to role %(role)s",
|
||||
{'user': user.id, 'role': role_id})
|
||||
self.client.roles.grant(role=role_id, user=user.id,
|
||||
project=self.context.tenant_id)
|
||||
project=self.context.project_id)
|
||||
else:
|
||||
LOG.error("Failed to add user %(user)s to role %(role)s, "
|
||||
"check role exists!",
|
||||
@ -439,10 +439,10 @@ class KsClientWrapper(object):
|
||||
if not self.stack_domain:
|
||||
# FIXME(shardy): Legacy fallback for folks using old heat.conf
|
||||
# files which lack domain configuration
|
||||
return self.context.tenant_id
|
||||
return self.context.project_id
|
||||
# Note we use the tenant ID not name to ensure uniqueness in a multi-
|
||||
# domain environment (where the tenant name may not be globally unique)
|
||||
project_name = ('%s-%s' % (self.context.tenant_id, stack_id))[:64]
|
||||
project_name = ('%s-%s' % (self.context.project_id, stack_id))[:64]
|
||||
desc = "Heat stack user project"
|
||||
domain_project = self.domain_admin_client.projects.create(
|
||||
name=project_name,
|
||||
@ -526,7 +526,7 @@ class KsClientWrapper(object):
|
||||
|
||||
def create_ec2_keypair(self, user_id=None):
|
||||
user_id = user_id or self.context.get_access(self.session).user_id
|
||||
project_id = self.context.tenant_id
|
||||
project_id = self.context.project_id
|
||||
data_blob = {'access': uuid.uuid4().hex,
|
||||
'secret': password_gen.generate_openstack_password()}
|
||||
ec2_creds = self.client.credentials.create(
|
||||
|
@ -101,7 +101,7 @@ class NeutronClientPlugin(os_client.ExtensionMixin,
|
||||
"""
|
||||
cmd_resource = (cmd_resource or
|
||||
self._res_cmdres_mapping.get(resource))
|
||||
return self._find_resource_id(self.context.tenant_id,
|
||||
return self._find_resource_id(self.context.project_id,
|
||||
resource, name_or_id,
|
||||
cmd_resource)
|
||||
|
||||
|
@ -259,7 +259,7 @@ class NovaClientPlugin(microversion_mixin.MicroversionMixin,
|
||||
:param flavor: the name of the flavor to find
|
||||
:returns: the id of :flavor:
|
||||
"""
|
||||
return self._find_flavor_id(self.context.tenant_id,
|
||||
return self._find_flavor_id(self.context.project_id,
|
||||
flavor)
|
||||
|
||||
@os_client.MEMOIZE_FINDER
|
||||
|
@ -86,7 +86,7 @@ class SwiftClientPlugin(client_plugin.ClientPlugin):
|
||||
return bool(len(parts) == 5 and
|
||||
not parts[0] and
|
||||
parts[1] == 'v1' and
|
||||
parts[2].endswith(self.context.tenant_id) and
|
||||
parts[2].endswith(self.context.project_id) and
|
||||
parts[3] and
|
||||
parts[4].strip('/'))
|
||||
|
||||
@ -102,7 +102,7 @@ class SwiftClientPlugin(client_plugin.ClientPlugin):
|
||||
|
||||
key = self.client().head_account()[key_header]
|
||||
|
||||
path = '/v1/AUTH_%s/%s/%s' % (self.context.tenant_id, container_name,
|
||||
path = '/v1/AUTH_%s/%s/%s' % (self.context.project_id, container_name,
|
||||
obj_name)
|
||||
if timeout is None:
|
||||
timeout = int(MAX_EPOCH - 60 - time.time())
|
||||
|
@ -705,7 +705,7 @@ class BaseCustomConstraint(object):
|
||||
return True
|
||||
class_name = reflection.get_class_name(self, fully_qualified=False)
|
||||
cache_value_prefix = "{0}:{1}".format(class_name,
|
||||
str(context.tenant_id))
|
||||
str(context.project_id))
|
||||
validation_result = check_cache_or_validate_value(
|
||||
cache_value_prefix, value)
|
||||
# if validation failed we should not store it in cache
|
||||
|
@ -77,7 +77,7 @@ class WaitCondition(heat_wc.HeatWaitCondition):
|
||||
def _validate_handle_url(self):
|
||||
handle_url = self.properties[self.HANDLE]
|
||||
handle_id = identifier.ResourceIdentifier.from_arn_url(handle_url)
|
||||
if handle_id.tenant != self.stack.context.tenant_id:
|
||||
if handle_id.tenant != self.stack.context.project_id:
|
||||
raise ValueError(_("WaitCondition invalid Handle tenant %s") %
|
||||
handle_id.tenant)
|
||||
if handle_id.stack_name != self.stack.name:
|
||||
|
@ -153,9 +153,9 @@ class HeatWaitConditionHandle(wc_base.BaseWaitConditionHandle):
|
||||
# the one needed for signalling from the stack_user_project
|
||||
heat_client_plugin = self.stack.clients.client_plugin('heat')
|
||||
endpoint = heat_client_plugin.get_heat_url()
|
||||
rsrc_ep = endpoint.replace(self.context.tenant_id,
|
||||
rsrc_ep = endpoint.replace(self.context.project_id,
|
||||
self.identifier().url_path())
|
||||
return rsrc_ep.replace(self.context.tenant_id,
|
||||
return rsrc_ep.replace(self.context.project_id,
|
||||
self.stack.stack_user_project_id)
|
||||
|
||||
def _resolve_attribute(self, key):
|
||||
|
@ -169,7 +169,7 @@ class NovaFlavor(resource.Resource):
|
||||
if not tenants:
|
||||
LOG.info('Tenant property is recommended '
|
||||
'for the private flavors.')
|
||||
tenant = self.stack.context.tenant_id
|
||||
tenant = self.stack.context.project_id
|
||||
self.client().flavor_access.add_tenant_access(flavor, tenant)
|
||||
else:
|
||||
for tenant in tenants:
|
||||
|
@ -345,7 +345,7 @@ class ServerNetworkMixin(object):
|
||||
|
||||
def _get_available_networks(self):
|
||||
# first we get the private networks owned by the tenant
|
||||
search_opts = {'tenant_id': self.context.tenant_id, 'shared': False,
|
||||
search_opts = {'tenant_id': self.context.project_id, 'shared': False,
|
||||
'admin_state_up': True, }
|
||||
nc = self.client('neutron')
|
||||
nets = nc.list_networks(**search_opts).get('networks', [])
|
||||
@ -359,7 +359,7 @@ class ServerNetworkMixin(object):
|
||||
|
||||
def _auto_allocate_network(self):
|
||||
topology = self.client('neutron').get_auto_allocated_topology(
|
||||
self.context.tenant_id)['auto_allocated_topology']
|
||||
self.context.project_id)['auto_allocated_topology']
|
||||
|
||||
return topology['id']
|
||||
|
||||
|
@ -137,7 +137,7 @@ class StackResource(resource.Resource):
|
||||
if self.resource_id is None:
|
||||
return None
|
||||
return identifier.HeatIdentifier(
|
||||
self.context.tenant_id,
|
||||
self.context.project_id,
|
||||
self.physical_resource_name(),
|
||||
self.resource_id)
|
||||
|
||||
|
@ -514,11 +514,11 @@ class EngineService(service.ServiceBase):
|
||||
raise exception.EntityNotFound(entity='Stack',
|
||||
name=identity.stack_name)
|
||||
|
||||
if not cnxt.is_admin and cnxt.tenant_id not in (
|
||||
if not cnxt.is_admin and cnxt.project_id not in (
|
||||
identity.tenant, s.stack_user_project_id):
|
||||
# The DB API should not allow this, but sanity-check anyway..
|
||||
raise exception.InvalidTenant(target=identity.tenant,
|
||||
actual=cnxt.tenant_id)
|
||||
actual=cnxt.project_id)
|
||||
|
||||
if identity.path or s.name != identity.stack_name:
|
||||
raise exception.EntityNotFound(entity='Stack',
|
||||
@ -2143,7 +2143,7 @@ class EngineService(service.ServiceBase):
|
||||
|
||||
with lock.thread_lock():
|
||||
snapshot = snapshot_object.Snapshot.create(cnxt, {
|
||||
'tenant': cnxt.tenant_id,
|
||||
'tenant': cnxt.project_id,
|
||||
'name': name,
|
||||
'stack_id': stack.id,
|
||||
'status': 'IN_PROGRESS'})
|
||||
|
@ -75,7 +75,7 @@ class SoftwareConfigService(object):
|
||||
rpc_api.SOFTWARE_CONFIG_OPTIONS: options,
|
||||
rpc_api.SOFTWARE_CONFIG_CONFIG: config
|
||||
},
|
||||
'tenant': cnxt.tenant_id})
|
||||
'tenant': cnxt.project_id})
|
||||
return api.format_software_config(sc)
|
||||
|
||||
def delete_software_config(self, cnxt, config_id):
|
||||
@ -290,7 +290,7 @@ class SoftwareConfigService(object):
|
||||
'config_id': config_id,
|
||||
'server_id': server_id,
|
||||
'input_values': input_values,
|
||||
'tenant': cnxt.tenant_id,
|
||||
'tenant': cnxt.project_id,
|
||||
'stack_user_project_id': stack_user_project_id,
|
||||
'action': action,
|
||||
'status': status,
|
||||
|
@ -206,7 +206,7 @@ class Stack(collections.abc.Mapping):
|
||||
|
||||
# This will use the provided tenant ID when loading the stack
|
||||
# from the DB or get it from the context for new stacks.
|
||||
self.tenant_id = tenant_id or self.context.tenant_id
|
||||
self.tenant_id = tenant_id or self.context.project_id
|
||||
self.username = username or self.context.username
|
||||
|
||||
resources.initialise()
|
||||
@ -553,7 +553,7 @@ class Stack(collections.abc.Mapping):
|
||||
stored_context = common_context.StoredContext.from_dict(creds)
|
||||
|
||||
if cfg.CONF.deferred_auth_method == 'trusts':
|
||||
old_trustor_proj_id = stored_context.tenant_id
|
||||
old_trustor_proj_id = stored_context.project_id
|
||||
old_trustor_user_id = stored_context.trustor_user_id
|
||||
|
||||
trustor_user_id = context.auth_plugin.get_user_id(
|
||||
|
@ -56,7 +56,7 @@ class ClientsTest(common.HeatTestCase):
|
||||
|
||||
def test_clients_get_heat_url(self):
|
||||
con = mock.Mock()
|
||||
con.tenant_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.project_id = "b363706f891f48019483f8bd6503c54b"
|
||||
c = clients.Clients(con)
|
||||
con.clients = c
|
||||
|
||||
@ -115,7 +115,7 @@ class ClientsTest(common.HeatTestCase):
|
||||
self.stub_keystoneclient()
|
||||
con = mock.Mock()
|
||||
con.auth_url = "http://auth.example.com:5000/v2.0"
|
||||
con.tenant_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.project_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.auth_token = "3bcc3d3a03f44e3d8377f9247b0ad155"
|
||||
c = clients.Clients(con)
|
||||
con.clients = c
|
||||
@ -130,7 +130,7 @@ class ClientsTest(common.HeatTestCase):
|
||||
def test_clients_heat_no_auth_token(self, mock_call):
|
||||
con = mock.Mock()
|
||||
con.auth_url = "http://auth.example.com:5000/v2.0"
|
||||
con.tenant_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.project_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.auth_token = None
|
||||
con.auth_plugin = fakes.FakeAuth(auth_token='anewtoken')
|
||||
c = clients.Clients(con)
|
||||
@ -146,7 +146,7 @@ class ClientsTest(common.HeatTestCase):
|
||||
self.stub_auth()
|
||||
con = mock.Mock()
|
||||
con.auth_url = "http://auth.example.com:5000/v2.0"
|
||||
con.tenant_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.project_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.auth_token = "3bcc3d3a03f44e3d8377f9247b0ad155"
|
||||
con.trust_id = None
|
||||
c = clients.Clients(con)
|
||||
@ -177,7 +177,7 @@ class ClientPluginTest(common.HeatTestCase):
|
||||
def test_get_client_option(self):
|
||||
con = mock.Mock()
|
||||
con.auth_url = "http://auth.example.com:5000/v2.0"
|
||||
con.tenant_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.project_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.auth_token = "3bcc3d3a03f44e3d8377f9247b0ad155"
|
||||
c = clients.Clients(con)
|
||||
con.clients = c
|
||||
@ -306,7 +306,7 @@ class TestClientPluginsInitialise(common.HeatTestCase):
|
||||
def test_create_all_clients(self):
|
||||
con = mock.Mock()
|
||||
con.auth_url = "http://auth.example.com:5000/v2.0"
|
||||
con.tenant_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.project_id = "b363706f891f48019483f8bd6503c54b"
|
||||
con.auth_token = "3bcc3d3a03f44e3d8377f9247b0ad155"
|
||||
c = clients.Clients(con)
|
||||
con.clients = c
|
||||
|
@ -213,11 +213,11 @@ class KeystoneClientTest(common.HeatTestCase):
|
||||
self.mock_ks_v3_client.users.create.assert_called_once_with(
|
||||
name=good_user_name,
|
||||
password='password',
|
||||
default_project=ctx.tenant_id)
|
||||
default_project=ctx.project_id)
|
||||
self.mock_ks_v3_client.roles.list.assert_called_once_with(
|
||||
name='heat_stack_user')
|
||||
self.mock_ks_v3_client.roles.grant.assert_called_once_with(
|
||||
project=ctx.tenant_id,
|
||||
project=ctx.project_id,
|
||||
role='4546',
|
||||
user='auser123')
|
||||
self._validate_stub_auth()
|
||||
@ -304,9 +304,9 @@ class KeystoneClientTest(common.HeatTestCase):
|
||||
self.mock_ks_v3_client.users.create.assert_called_once_with(
|
||||
name='auser',
|
||||
password='password',
|
||||
default_project=ctx.tenant_id)
|
||||
default_project=ctx.project_id)
|
||||
self.mock_ks_v3_client.roles.grant.assert_called_once_with(
|
||||
project=ctx.tenant_id,
|
||||
project=ctx.project_id,
|
||||
role='4546',
|
||||
user='auser123')
|
||||
self.mock_ks_v3_client.roles.list.assert_called_once_with(
|
||||
@ -1138,7 +1138,7 @@ class KeystoneClientTest(common.HeatTestCase):
|
||||
self.assertEqual('dummy_secret', ec2_cred.secret)
|
||||
self.mock_ks_v3_client.credentials.create.assert_called_once_with(
|
||||
user='atestuser', type='ec2', blob=ex_data_json,
|
||||
project=ctx.tenant_id)
|
||||
project=ctx.project_id)
|
||||
self._validate_stub_auth()
|
||||
|
||||
def test_create_stack_domain_user_keypair(self):
|
||||
@ -1212,7 +1212,7 @@ class KeystoneClientTest(common.HeatTestCase):
|
||||
self.assertEqual('dummy_secret2', ec2_cred.secret)
|
||||
self.mock_ks_v3_client.credentials.create.assert_called_once_with(
|
||||
user='atestuser2', type='ec2', blob=ex_data_json,
|
||||
project=ctx.tenant_id)
|
||||
project=ctx.project_id)
|
||||
self._validate_stub_auth()
|
||||
|
||||
def test_get_ec2_keypair_id(self):
|
||||
@ -1353,7 +1353,7 @@ class KeystoneClientTest(common.HeatTestCase):
|
||||
ctx = utils.dummy_context()
|
||||
self.patchobject(ctx, '_create_auth_plugin')
|
||||
ctx.trust_id = None
|
||||
expected_name = '%s-astack' % ctx.tenant_id
|
||||
expected_name = '%s-astack' % ctx.project_id
|
||||
|
||||
self._stub_domain_admin_client()
|
||||
dummy = mock.Mock()
|
||||
@ -1377,7 +1377,7 @@ class KeystoneClientTest(common.HeatTestCase):
|
||||
ctx.trust_id = None
|
||||
self.patchobject(ctx, '_create_auth_plugin')
|
||||
heat_ks_client = heat_keystoneclient.KeystoneClient(ctx)
|
||||
self.assertEqual(ctx.tenant_id,
|
||||
self.assertEqual(ctx.project_id,
|
||||
heat_ks_client.create_stack_domain_project('astack'))
|
||||
|
||||
def test_delete_stack_domain_project(self):
|
||||
|
@ -1049,7 +1049,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
self.assertIsNone(load_creds.get('region_name'))
|
||||
|
||||
def test_software_config_create(self):
|
||||
tenant_id = self.ctx.tenant_id
|
||||
tenant_id = self.ctx.project_id
|
||||
config = db_api.software_config_create(
|
||||
self.ctx, {'name': 'config_mysql',
|
||||
'tenant': tenant_id})
|
||||
@ -1071,7 +1071,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
'config': conf,
|
||||
'options': {}
|
||||
}
|
||||
tenant_id = self.ctx.tenant_id
|
||||
tenant_id = self.ctx.project_id
|
||||
values = {'name': 'config_mysql',
|
||||
'tenant': tenant_id,
|
||||
'group': 'Heat::Shell',
|
||||
@ -1098,7 +1098,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
self.assertIsNotNone(config)
|
||||
|
||||
def _create_software_config_record(self):
|
||||
tenant_id = self.ctx.tenant_id
|
||||
tenant_id = self.ctx.project_id
|
||||
software_config = db_api.software_config_create(
|
||||
self.ctx, {'name': 'config_mysql',
|
||||
'tenant': tenant_id})
|
||||
@ -1156,7 +1156,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
db_api.software_config_delete(admin_ctx, scf_id)
|
||||
|
||||
def test_software_config_delete_not_allowed(self):
|
||||
tenant_id = self.ctx.tenant_id
|
||||
tenant_id = self.ctx.project_id
|
||||
config = db_api.software_config_create(
|
||||
self.ctx, {'name': 'config_mysql',
|
||||
'tenant': tenant_id})
|
||||
@ -1176,7 +1176,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
self.assertIn(msg, str(err))
|
||||
|
||||
def _deployment_values(self):
|
||||
tenant_id = self.ctx.tenant_id
|
||||
tenant_id = self.ctx.project_id
|
||||
stack_user_project_id = str(uuid.uuid4())
|
||||
config_id = db_api.software_config_create(
|
||||
self.ctx, {'name': 'config_mysql', 'tenant': tenant_id}).id
|
||||
@ -1325,7 +1325,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
template = create_raw_template(self.ctx)
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
self.assertIsNotNone(snapshot)
|
||||
@ -1335,7 +1335,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
template = create_raw_template(self.ctx)
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id, 'name': 'snap1'}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
self.assertIsNotNone(snapshot)
|
||||
@ -1353,7 +1353,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
template = create_raw_template(self.ctx)
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
self.assertIsNotNone(snapshot)
|
||||
@ -1369,7 +1369,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
stack1 = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
self.assertIsNotNone(snapshot)
|
||||
@ -1382,7 +1382,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
template = create_raw_template(self.ctx)
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
self.ctx.project_id = str(uuid.uuid4())
|
||||
@ -1403,7 +1403,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
template = create_raw_template(self.ctx)
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
snapshot_id = snapshot.id
|
||||
@ -1423,7 +1423,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
template = create_raw_template(self.ctx)
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
snapshot_id = snapshot.id
|
||||
@ -1443,7 +1443,7 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
template = create_raw_template(self.ctx)
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
stack = create_stack(self.ctx, template, user_creds)
|
||||
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
||||
values = {'tenant': self.ctx.project_id, 'status': 'IN_PROGRESS',
|
||||
'stack_id': stack.id}
|
||||
snapshot = db_api.snapshot_create(self.ctx, values)
|
||||
self.assertIsNotNone(snapshot)
|
||||
@ -1460,19 +1460,19 @@ class SqlAlchemyTest(common.HeatTestCase):
|
||||
stack2 = create_stack(self.ctx, template, user_creds)
|
||||
values = [
|
||||
{
|
||||
'tenant': self.ctx.tenant_id,
|
||||
'tenant': self.ctx.project_id,
|
||||
'status': 'IN_PROGRESS',
|
||||
'stack_id': stack1.id,
|
||||
'name': 'snp1'
|
||||
},
|
||||
{
|
||||
'tenant': self.ctx.tenant_id,
|
||||
'tenant': self.ctx.project_id,
|
||||
'status': 'IN_PROGRESS',
|
||||
'stack_id': stack1.id,
|
||||
'name': 'snp1'
|
||||
},
|
||||
{
|
||||
'tenant': self.ctx.tenant_id,
|
||||
'tenant': self.ctx.project_id,
|
||||
'status': 'IN_PROGRESS',
|
||||
'stack_id': stack2.id,
|
||||
'name': 'snp2'
|
||||
@ -1703,7 +1703,7 @@ class DBAPIUserCredsTest(common.HeatTestCase):
|
||||
self.assertIsNone(user_creds['username'])
|
||||
self.assertIsNone(user_creds['password'])
|
||||
self.assertEqual(self.ctx.project_name, user_creds['tenant'])
|
||||
self.assertEqual(self.ctx.tenant_id, user_creds['tenant_id'])
|
||||
self.assertEqual(self.ctx.project_id, user_creds['tenant_id'])
|
||||
|
||||
def test_user_creds_create_password(self):
|
||||
user_creds = create_user_creds(self.ctx)
|
||||
@ -1798,7 +1798,7 @@ class DBAPIStackTest(common.HeatTestCase):
|
||||
self.assertEqual(12, len(stack.name))
|
||||
self.assertEqual(self.template.id, stack.raw_template_id)
|
||||
self.assertEqual(self.ctx.username, stack.username)
|
||||
self.assertEqual(self.ctx.tenant_id, stack.tenant)
|
||||
self.assertEqual(self.ctx.project_id, stack.tenant)
|
||||
self.assertEqual('create', stack.action)
|
||||
self.assertEqual('complete', stack.status)
|
||||
self.assertEqual('create_complete', stack.status_reason)
|
||||
|
@ -103,7 +103,7 @@ class StackResourcesServiceTest(common.HeatTestCase):
|
||||
@mock.patch.object(service.EngineService, '_get_stack')
|
||||
def test_stack_resource_describe_nonexist_stack(self, mock_get):
|
||||
non_exist_identifier = identifier.HeatIdentifier(
|
||||
self.ctx.tenant_id, 'wibble',
|
||||
self.ctx.project_id, 'wibble',
|
||||
'18d06e2e-44d3-4bef-9fbf-52480d604b02')
|
||||
mock_get.side_effect = exception.EntityNotFound(
|
||||
entity='Stack', name='test')
|
||||
@ -194,7 +194,7 @@ class StackResourcesServiceTest(common.HeatTestCase):
|
||||
|
||||
def test_stack_resources_describe_nonexist_stack(self):
|
||||
non_exist_identifier = identifier.HeatIdentifier(
|
||||
self.ctx.tenant_id, 'wibble',
|
||||
self.ctx.project_id, 'wibble',
|
||||
'18d06e2e-44d3-4bef-9fbf-52480d604b02')
|
||||
|
||||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
@ -307,7 +307,7 @@ class StackResourcesServiceTest(common.HeatTestCase):
|
||||
@mock.patch.object(service.EngineService, '_get_stack')
|
||||
def test_stack_resources_list_nonexist_stack(self, mock_get):
|
||||
non_exist_identifier = identifier.HeatIdentifier(
|
||||
self.ctx.tenant_id, 'wibble',
|
||||
self.ctx.project_id, 'wibble',
|
||||
'18d06e2e-44d3-4bef-9fbf-52480d604b02')
|
||||
mock_get.side_effect = exception.EntityNotFound(entity='Stack',
|
||||
name='test')
|
||||
|
@ -146,7 +146,7 @@ class TestRequestContext(common.HeatTestCase):
|
||||
continue
|
||||
|
||||
# these values are different between attribute and context
|
||||
if k == 'tenant' or k == 'user':
|
||||
if k in ('tenant', 'user', 'tenant_id'):
|
||||
continue
|
||||
|
||||
self.assertEqual(self.ctx.get(k), ctx.to_dict().get(k))
|
||||
|
@ -541,7 +541,7 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
snapshot_values = {
|
||||
'stack_id': stack.id,
|
||||
'name': 'fake_snapshot',
|
||||
'tenant': stack.context.tenant_id,
|
||||
'tenant': stack.context.project_id,
|
||||
'status': 'COMPLETE',
|
||||
'data': None
|
||||
}
|
||||
|
@ -724,7 +724,7 @@ class StackServiceTest(common.HeatTestCase):
|
||||
|
||||
def test_stack_describe_nonexistent(self):
|
||||
non_exist_identifier = identifier.HeatIdentifier(
|
||||
self.ctx.tenant_id, 'wibble',
|
||||
self.ctx.project_id, 'wibble',
|
||||
'18d06e2e-44d3-4bef-9fbf-52480d604b02')
|
||||
|
||||
stack_not_found_exc = exception.EntityNotFound(
|
||||
|
@ -200,7 +200,7 @@ class EventTest(EventCommon):
|
||||
expected_identifier = {
|
||||
'stack_name': self.stack.name,
|
||||
'stack_id': self.stack.id,
|
||||
'tenant': self.ctx.tenant_id,
|
||||
'tenant': self.ctx.project_id,
|
||||
'path': '/resources/EventTestResource/events/%s' % str(event_uuid)
|
||||
}
|
||||
self.assertEqual(expected_identifier, e.identifier())
|
||||
|
@ -422,7 +422,7 @@ Outputs:
|
||||
self.res.action = self.res.CREATE
|
||||
self.res.nested_identifier = mock.MagicMock()
|
||||
stack_identity = identifier.HeatIdentifier(
|
||||
self.ctx.tenant_id,
|
||||
self.ctx.project_id,
|
||||
self.res.physical_resource_name(),
|
||||
self.res.resource_id)
|
||||
self.res.nested_identifier.return_value = stack_identity
|
||||
|
@ -1009,7 +1009,7 @@ class TemplateResourceCrudTest(common.HeatTestCase):
|
||||
self.res.resource_id = str(uuid.uuid4())
|
||||
self.res.action = self.res.CREATE
|
||||
self.res.nested = mock.MagicMock()
|
||||
ident = identifier.HeatIdentifier(self.ctx.tenant_id,
|
||||
ident = identifier.HeatIdentifier(self.ctx.project_id,
|
||||
self.res.physical_resource_name(),
|
||||
self.res.resource_id)
|
||||
self.res.nested().identifier.return_value = ident
|
||||
|
@ -504,10 +504,10 @@ class StackTest(common.HeatTestCase):
|
||||
"resource_id": null, "action": "INIT", "type": "GenericResourceType",
|
||||
"metadata": {}}}'''
|
||||
env = environment.Environment({'parameters': {'param1': 'test'}})
|
||||
self.ctx.tenant_id = '123'
|
||||
self.ctx.project_id = '123'
|
||||
self.stack = stack.Stack(self.ctx, 'stack_details_test',
|
||||
template.Template(tpl, env=env),
|
||||
tenant_id=self.ctx.tenant_id,
|
||||
tenant_id=self.ctx.project_id,
|
||||
stack_user_project_id='234',
|
||||
tags=['tag1', 'tag2'])
|
||||
self.stack.store()
|
||||
|
@ -65,7 +65,7 @@ class StackTest(common.HeatTestCase):
|
||||
self.stack = stack.Stack(self.ctx, 'delete_test', self.tmpl)
|
||||
stack_id = self.stack.store()
|
||||
snapshot_fake = {
|
||||
'tenant': self.ctx.tenant_id,
|
||||
'tenant': self.ctx.project_id,
|
||||
'name': 'Snapshot',
|
||||
'stack_id': stack_id,
|
||||
'status': 'COMPLETE',
|
||||
@ -96,7 +96,7 @@ class StackTest(common.HeatTestCase):
|
||||
data = copy.deepcopy(self.stack.prepare_abandon())
|
||||
data['resources']['A']['resource_data']['a_string'] = 'foo'
|
||||
snapshot_fake = {
|
||||
'tenant': self.ctx.tenant_id,
|
||||
'tenant': self.ctx.project_id,
|
||||
'name': 'Snapshot',
|
||||
'stack_id': stack_id,
|
||||
'status': 'COMPLETE',
|
||||
|
@ -980,7 +980,7 @@ class WithTemplateTest(StackResourceBaseTest):
|
||||
def test_update_with_template(self):
|
||||
if self.adopt_data is not None:
|
||||
return
|
||||
ident = identifier.HeatIdentifier(self.ctx.tenant_id, 'fake_name',
|
||||
ident = identifier.HeatIdentifier(self.ctx.project_id, 'fake_name',
|
||||
'pancakes')
|
||||
self.parent_resource.resource_id = ident.stack_id
|
||||
self.parent_resource.nested_identifier = mock.Mock(return_value=ident)
|
||||
@ -1014,7 +1014,7 @@ class WithTemplateTest(StackResourceBaseTest):
|
||||
|
||||
if self.adopt_data is not None:
|
||||
return
|
||||
ident = identifier.HeatIdentifier(self.ctx.tenant_id, 'fake_name',
|
||||
ident = identifier.HeatIdentifier(self.ctx.project_id, 'fake_name',
|
||||
'pancakes')
|
||||
self.parent_resource.resource_id = ident.stack_id
|
||||
self.parent_resource.nested_identifier = mock.Mock(return_value=ident)
|
||||
|
@ -102,7 +102,7 @@ def dummy_system_admin_context():
|
||||
ctx = dummy_context(roles=['admin', 'member', 'reader'])
|
||||
ctx.system_scope = 'all'
|
||||
ctx.project_id = None
|
||||
ctx.tenant_id = None
|
||||
ctx.project_id = None
|
||||
return ctx
|
||||
|
||||
|
||||
@ -115,7 +115,7 @@ def dummy_system_reader_context():
|
||||
ctx = dummy_context(roles=['reader'])
|
||||
ctx.system_scope = 'all'
|
||||
ctx.project_id = None
|
||||
ctx.tenant_id = None
|
||||
ctx.project_id = None
|
||||
return ctx
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user