Merge "reuse the deleted image-member before create a new image-member"
This commit is contained in:
commit
5e606c32bb
|
@ -353,8 +353,22 @@ class ImageMemberRepo(object):
|
|||
raise exception.Duplicate(msg)
|
||||
|
||||
image_member_values = self._format_image_member_to_db(image_member)
|
||||
new_values = self.db_api.image_member_create(self.context,
|
||||
image_member_values)
|
||||
# Note(shalq): find the image member including the member marked with
|
||||
# deleted. We will use only one record to represent membership between
|
||||
# the same image and member. The record of the deleted image member
|
||||
# will be reused, if it exists, update its properties instead of
|
||||
# creating a new one.
|
||||
members = self.db_api.image_member_find(self.context,
|
||||
image_id=self.image.image_id,
|
||||
member=image_member.member_id,
|
||||
include_deleted=True)
|
||||
if members:
|
||||
new_values = self.db_api.image_member_update(self.context,
|
||||
members[0]['id'],
|
||||
image_member_values)
|
||||
else:
|
||||
new_values = self.db_api.image_member_create(self.context,
|
||||
image_member_values)
|
||||
image_member.created_at = new_values['created_at']
|
||||
image_member.updated_at = new_values['updated_at']
|
||||
image_member.id = new_values['id']
|
||||
|
|
|
@ -188,15 +188,24 @@ def image_member_delete(client, memb_id, session=None):
|
|||
|
||||
|
||||
@_get_client
|
||||
def image_member_find(client, image_id=None, member=None, status=None):
|
||||
"""Find all members that meet the given criteria
|
||||
def image_member_find(client, image_id=None, member=None, status=None,
|
||||
include_deleted=False):
|
||||
"""Find all members that meet the given criteria.
|
||||
|
||||
Note, currently include_deleted should be true only when create a new
|
||||
image membership, as there may be a deleted image membership between
|
||||
the same image and tenant, the membership will be reused in this case.
|
||||
It should be false in other cases.
|
||||
|
||||
:param image_id: identifier of image entity
|
||||
:param member: tenant to which membership has been granted
|
||||
:include_deleted: A boolean indicating whether the result should include
|
||||
the deleted record of image member
|
||||
"""
|
||||
return client.image_member_find(image_id=image_id,
|
||||
member=member,
|
||||
status=status)
|
||||
status=status,
|
||||
include_deleted=include_deleted)
|
||||
|
||||
|
||||
@_get_client
|
||||
|
|
|
@ -454,7 +454,8 @@ def image_property_delete(context, prop_ref, image_ref):
|
|||
|
||||
|
||||
@log_call
|
||||
def image_member_find(context, image_id=None, member=None, status=None):
|
||||
def image_member_find(context, image_id=None, member=None,
|
||||
status=None, include_deleted=False):
|
||||
filters = []
|
||||
images = DATA['images']
|
||||
members = DATA['members']
|
||||
|
|
|
@ -1075,21 +1075,31 @@ def _image_member_get(context, memb_id, session):
|
|||
return query.one()
|
||||
|
||||
|
||||
def image_member_find(context, image_id=None, member=None, status=None):
|
||||
"""Find all members that meet the given criteria
|
||||
def image_member_find(context, image_id=None, member=None,
|
||||
status=None, include_deleted=False):
|
||||
"""Find all members that meet the given criteria.
|
||||
|
||||
Note, currently include_deleted should be true only when create a new
|
||||
image membership, as there may be a deleted image membership between
|
||||
the same image and tenant, the membership will be reused in this case.
|
||||
It should be false in other cases.
|
||||
|
||||
:param image_id: identifier of image entity
|
||||
:param member: tenant to which membership has been granted
|
||||
:include_deleted: A boolean indicating whether the result should include
|
||||
the deleted record of image member
|
||||
"""
|
||||
session = get_session()
|
||||
members = _image_member_find(context, session, image_id, member, status)
|
||||
members = _image_member_find(context, session, image_id,
|
||||
member, status, include_deleted)
|
||||
return [_image_member_format(m) for m in members]
|
||||
|
||||
|
||||
def _image_member_find(context, session, image_id=None,
|
||||
member=None, status=None):
|
||||
member=None, status=None, include_deleted=False):
|
||||
query = session.query(models.ImageMember)
|
||||
query = query.filter_by(deleted=False)
|
||||
if not include_deleted:
|
||||
query = query.filter_by(deleted=False)
|
||||
|
||||
if not context.is_admin:
|
||||
query = query.join(models.Image)
|
||||
|
|
|
@ -158,7 +158,8 @@ class Controller(object):
|
|||
# Try to find the corresponding membership
|
||||
members = self.db_api.image_member_find(req.context,
|
||||
image_id=datum['image_id'],
|
||||
member=datum['member'])
|
||||
member=datum['member'],
|
||||
include_deleted=True)
|
||||
try:
|
||||
member = members[0]
|
||||
except IndexError:
|
||||
|
@ -257,7 +258,8 @@ class Controller(object):
|
|||
# Look up an existing membership...
|
||||
members = self.db_api.image_member_find(req.context,
|
||||
image_id=image_id,
|
||||
member=id)
|
||||
member=id,
|
||||
include_deleted=True)
|
||||
if members:
|
||||
if can_share is not None:
|
||||
values = dict(can_share=can_share)
|
||||
|
|
|
@ -1766,6 +1766,49 @@ class TestRegistryAPI(base.IsolatedUnitTest, test_utils.RegistryAPIMixIn):
|
|||
res = req.get_response(api)
|
||||
self.assertEqual(res.status_int, 403)
|
||||
|
||||
def test_add_member_delete_create(self):
|
||||
"""
|
||||
Test check that the same member can be successfully added after delete
|
||||
it, and the same record will be reused for the same membership.
|
||||
"""
|
||||
# add a member
|
||||
UUID8 = _gen_uuid()
|
||||
extra_fixture = self.get_fixture(id=UUID8, size=19, protected=False,
|
||||
owner='test user')
|
||||
|
||||
db_api.image_create(self.context, extra_fixture)
|
||||
fixture = dict(can_share=True)
|
||||
test_uri = '/images/%s/members/test_add_member_delete_create'
|
||||
body = jsonutils.dumps(dict(member=fixture))
|
||||
self.get_api_response_ext(204, url=test_uri % UUID8,
|
||||
method='PUT', body=body,
|
||||
content_type='json')
|
||||
memb_list = db_api.image_member_find(self.context, image_id=UUID8)
|
||||
self.assertEqual(1, len(memb_list))
|
||||
memb_list2 = db_api.image_member_find(self.context,
|
||||
image_id=UUID8,
|
||||
include_deleted=True)
|
||||
self.assertEqual(1, len(memb_list2))
|
||||
# delete the member
|
||||
self.get_api_response_ext(204, method='DELETE',
|
||||
url=test_uri % UUID8)
|
||||
memb_list = db_api.image_member_find(self.context, image_id=UUID8)
|
||||
self.assertEqual(0, len(memb_list))
|
||||
memb_list2 = db_api.image_member_find(self.context,
|
||||
image_id=UUID8,
|
||||
include_deleted=True)
|
||||
self.assertEqual(1, len(memb_list2))
|
||||
# create it again
|
||||
self.get_api_response_ext(204, url=test_uri % UUID8,
|
||||
method='PUT', body=body,
|
||||
content_type='json')
|
||||
memb_list = db_api.image_member_find(self.context, image_id=UUID8)
|
||||
self.assertEqual(1, len(memb_list))
|
||||
memb_list2 = db_api.image_member_find(self.context,
|
||||
image_id=UUID8,
|
||||
include_deleted=True)
|
||||
self.assertEqual(1, len(memb_list2))
|
||||
|
||||
def test_get_on_image_member(self):
|
||||
"""
|
||||
Test GET on image members raises 405 and produces correct Allow headers
|
||||
|
|
|
@ -677,6 +677,31 @@ class TestRegistryV2Client(base.IsolatedUnitTest,
|
|||
num_members = len(memb_list)
|
||||
self.assertEqual(0, num_members)
|
||||
|
||||
def test_image_member_find_include_deleted(self):
|
||||
"""Tests getting member images include the delted member"""
|
||||
values = dict(image_id=UUID2, member='pattieblack')
|
||||
# create a member
|
||||
member = self.client.image_member_create(values=values)
|
||||
memb_list = self.client.image_member_find(member='pattieblack')
|
||||
memb_list2 = self.client.image_member_find(member='pattieblack',
|
||||
include_deleted=True)
|
||||
self.assertEqual(1, len(memb_list))
|
||||
self.assertEqual(1, len(memb_list2))
|
||||
# delete the member
|
||||
self.client.image_member_delete(memb_id=member['id'])
|
||||
memb_list = self.client.image_member_find(member='pattieblack')
|
||||
memb_list2 = self.client.image_member_find(member='pattieblack',
|
||||
include_deleted=True)
|
||||
self.assertEqual(0, len(memb_list))
|
||||
self.assertEqual(1, len(memb_list2))
|
||||
# create it again
|
||||
member = self.client.image_member_create(values=values)
|
||||
memb_list = self.client.image_member_find(member='pattieblack')
|
||||
memb_list2 = self.client.image_member_find(member='pattieblack',
|
||||
include_deleted=True)
|
||||
self.assertEqual(1, len(memb_list))
|
||||
self.assertEqual(2, len(memb_list2))
|
||||
|
||||
def test_add_update_members(self):
|
||||
"""Tests updating image members"""
|
||||
values = dict(image_id=UUID2, member='pattieblack')
|
||||
|
|
Loading…
Reference in New Issue