Fix default approach for share group snapshot creation
Default approach uses common driver interface of single snapshot creation. So, emulate it correctly providing all required keys. Also add 'provider_location' attribute to share group snapshot members DB model, because it is required for some drivers and was absent. Change-Id: If120d85ef3dd3ba90e2dc12a5b81b69feecb31ea Closes-Bug: #1660321
This commit is contained in:
parent
7c2c97d725
commit
64649b97e7
manila
api/views
db
migrations/alembic/versions
sqlalchemy
share
tests
releasenotes/notes
@ -41,6 +41,7 @@ class ShareGroupSnapshotViewBuilder(common.ViewBuilder):
|
||||
'share_group_snapshot_id': member.get(
|
||||
'share_group_snapshot_id'),
|
||||
'share_id': member.get('share_id'),
|
||||
# TODO(vponomaryov): add 'provider_location' key in Pike.
|
||||
}
|
||||
members_list.append(member_dict)
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
# 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.
|
||||
|
||||
"""Add 'provider_location' attr to 'share_group_snapshot_members' model.
|
||||
|
||||
Revision ID: 927920b37453
|
||||
Revises: a77e2ad5012d
|
||||
Create Date: 2017-01-31 20:10:44.937763
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '927920b37453'
|
||||
down_revision = 'a77e2ad5012d'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
SGSM_TABLE_NAME = 'share_group_snapshot_members'
|
||||
PROVIDER_LOCATION_NAME = 'provider_location'
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column(
|
||||
SGSM_TABLE_NAME,
|
||||
sa.Column(PROVIDER_LOCATION_NAME, sa.String(255), nullable=True),
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column(SGSM_TABLE_NAME, PROVIDER_LOCATION_NAME)
|
@ -1148,14 +1148,20 @@ class ShareGroupShareTypeMapping(BASE, ManilaBase):
|
||||
'ShareGroupShareTypeMapping.deleted == "False")')
|
||||
)
|
||||
|
||||
# TODO(vponomaryov): add 'share_group_snapshot_member_export_locations' model
|
||||
# to support mountable share group snapshots and add its relationship to
|
||||
# 'share_group_snapshot_members' table.
|
||||
|
||||
|
||||
class ShareGroupSnapshotMember(BASE, ManilaBase):
|
||||
"""Represents the share snapshots in a share group snapshot."""
|
||||
__tablename__ = 'share_group_snapshot_members'
|
||||
id = Column(String(36), primary_key=True)
|
||||
# TODO(vponomaryov): make 'share_group_snapshot_id' not nullable.
|
||||
share_group_snapshot_id = Column(
|
||||
String(36), ForeignKey('share_group_snapshots.id'))
|
||||
share_id = Column(String(36), ForeignKey('shares.id'))
|
||||
# TODO(vponomaryov): make 'share_instance_id' not nullable.
|
||||
share_instance_id = Column(String(36), ForeignKey('share_instances.id'))
|
||||
size = Column(Integer)
|
||||
status = Column(String(255))
|
||||
@ -1163,6 +1169,11 @@ class ShareGroupSnapshotMember(BASE, ManilaBase):
|
||||
user_id = Column(String(255))
|
||||
project_id = Column(String(255))
|
||||
deleted = Column(String(36), default='False')
|
||||
provider_location = Column(String(255))
|
||||
# TODO(vponomaryov): add relationship to source share instance as it is
|
||||
# done for share snapshot instances.
|
||||
# TODO(vponomaryov): add share group snapshot member export locations
|
||||
# relationship.
|
||||
share_group_snapshot = orm.relationship(
|
||||
ShareGroupSnapshot,
|
||||
backref="share_group_snapshot_members",
|
||||
|
@ -1325,7 +1325,8 @@ class ShareDriver(object):
|
||||
'deleted_at': None,
|
||||
'share_id': 'some_fake_uuid',
|
||||
'id': 'some_fake_uuid',
|
||||
'size': 1
|
||||
'size': 1,
|
||||
'provider_location': None,
|
||||
}
|
||||
],
|
||||
'deleted_at': None,
|
||||
@ -1350,17 +1351,28 @@ class ShareDriver(object):
|
||||
share_group=snap_dict['share_group_id'])
|
||||
elif not snapshot_members:
|
||||
LOG.warning(_LW('No shares in share group to create snapshot.'))
|
||||
return None, None
|
||||
else:
|
||||
share_snapshots = []
|
||||
snapshot_members_updates = []
|
||||
for member in snapshot_members:
|
||||
share_snapshot = {
|
||||
'snapshot_id': member['share_group_snapshot_id'],
|
||||
'share_id': member['share_id'],
|
||||
'share_instance_id': member['share']['id'],
|
||||
'id': member['id'],
|
||||
'share': member['share'],
|
||||
'size': member['share']['size'],
|
||||
'share_size': member['share']['size'],
|
||||
'share_proto': member['share']['share_proto'],
|
||||
'provider_location': None,
|
||||
}
|
||||
try:
|
||||
self.create_snapshot(context, share_snapshot,
|
||||
share_server=share_server)
|
||||
member_update = self.create_snapshot(
|
||||
context, share_snapshot, share_server=share_server)
|
||||
if member_update:
|
||||
member_update['id'] = member['id']
|
||||
snapshot_members_updates.append(member_update)
|
||||
share_snapshots.append(share_snapshot)
|
||||
except exception.ManilaException as e:
|
||||
msg = _LE('Could not create share group snapshot. Failed '
|
||||
@ -1381,8 +1393,7 @@ class ShareDriver(object):
|
||||
|
||||
LOG.debug('Successfully created share group snapshot %s.',
|
||||
snap_dict['id'])
|
||||
|
||||
return None, None
|
||||
return None, snapshot_members_updates
|
||||
|
||||
def delete_share_group_snapshot(self, context, snap_dict,
|
||||
share_server=None):
|
||||
@ -1417,7 +1428,8 @@ class ShareDriver(object):
|
||||
'share_group_snapshot_id': 'some_fake_uuid',
|
||||
'deleted_at': None,
|
||||
'id': 'some_fake_uuid',
|
||||
'size': 1
|
||||
'size': 1,
|
||||
'provider_location': 'fake_provider_location_value',
|
||||
}
|
||||
],
|
||||
'deleted_at': None,
|
||||
@ -1433,8 +1445,15 @@ class ShareDriver(object):
|
||||
LOG.debug('Deleting share group snapshot %s.' % snap_dict['id'])
|
||||
for member in snapshot_members:
|
||||
share_snapshot = {
|
||||
'snapshot_id': member['share_group_snapshot_id'],
|
||||
'share_id': member['share_id'],
|
||||
'share_instance_id': member['share']['id'],
|
||||
'id': member['id'],
|
||||
'share': member['share'],
|
||||
'size': member['share']['size'],
|
||||
'share_size': member['share']['size'],
|
||||
'share_proto': member['share']['share_proto'],
|
||||
'provider_location': member['provider_location'],
|
||||
}
|
||||
self.delete_snapshot(
|
||||
context, share_snapshot, share_server=share_server)
|
||||
|
@ -3589,6 +3589,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
member['share_id'] = member['share_instance_id']
|
||||
|
||||
status = constants.STATUS_AVAILABLE
|
||||
now = timeutils.utcnow()
|
||||
updated_members_ids = []
|
||||
|
||||
try:
|
||||
LOG.info(_LI("Share group snapshot %s: creating"),
|
||||
@ -3601,12 +3603,51 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
self.driver.create_share_group_snapshot(
|
||||
context, snap_ref, share_server=share_server))
|
||||
|
||||
if member_update_list:
|
||||
snapshot_update = snapshot_update or {}
|
||||
snapshot_update['share_group_snapshot_members'] = []
|
||||
for update in (member_update_list or []):
|
||||
snapshot_update['share_group_snapshot_members'].append(
|
||||
update)
|
||||
for update in (member_update_list or []):
|
||||
# NOTE(vponomaryov): we expect that each member is a dict
|
||||
# and has required 'id' key and some optional keys
|
||||
# to be updated such as 'provider_location'. It is planned
|
||||
# to have here also 'export_locations' when it is supported.
|
||||
member_id = update.pop('id', None)
|
||||
if not member_id:
|
||||
LOG.warning(_LW(
|
||||
"One of share group snapshot '%s' members does not "
|
||||
"have reference ID. Its update was skipped."),
|
||||
share_group_snapshot_id)
|
||||
continue
|
||||
# TODO(vponomaryov): remove following condition when
|
||||
# sgs members start supporting export locations.
|
||||
if 'export_locations' in update:
|
||||
LOG.debug(
|
||||
"Removing 'export_locations' data from "
|
||||
"share group snapshot member '%s' update because "
|
||||
"export locations are not supported.",
|
||||
member_id)
|
||||
update.pop('export_locations')
|
||||
|
||||
db_update = {
|
||||
'updated_at': now,
|
||||
'status': update.pop('status', status)
|
||||
}
|
||||
if 'provider_location' in update:
|
||||
db_update['provider_location'] = (
|
||||
update.pop('provider_location'))
|
||||
if 'size' in update:
|
||||
db_update['size'] = int(update.pop('size'))
|
||||
|
||||
updated_members_ids.append(member_id)
|
||||
self.db.share_group_snapshot_member_update(
|
||||
context, member_id, db_update)
|
||||
|
||||
if update:
|
||||
LOG.debug(
|
||||
"Share group snapshot ID='%(sgs_id)s', "
|
||||
"share group snapshot member ID='%(sgsm_id)s'. "
|
||||
"Following keys of sgs member were not updated "
|
||||
"as not allowed: %(keys)s.",
|
||||
{'sgs_id': share_group_snapshot_id,
|
||||
'sgsm_id': member_id,
|
||||
'keys': ', '.join(update)})
|
||||
|
||||
if snapshot_update:
|
||||
snap_ref = self.db.share_group_snapshot_update(
|
||||
@ -3621,15 +3662,16 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
LOG.error(_LE("Share group snapshot %s: create failed"),
|
||||
share_group_snapshot_id)
|
||||
|
||||
now = timeutils.utcnow()
|
||||
for member in (snap_ref.get('share_group_snapshot_members') or []):
|
||||
update = {'status': status, 'created_at': now}
|
||||
if member['id'] in updated_members_ids:
|
||||
continue
|
||||
update = {'status': status, 'updated_at': now}
|
||||
self.db.share_group_snapshot_member_update(
|
||||
context, member['id'], update)
|
||||
|
||||
self.db.share_group_snapshot_update(
|
||||
context, snap_ref['id'],
|
||||
{'status': status, 'created_at': now})
|
||||
{'status': status, 'updated_at': now})
|
||||
LOG.info(_LI("Share group snapshot %s: created successfully"),
|
||||
share_group_snapshot_id)
|
||||
|
||||
|
@ -2016,3 +2016,96 @@ class ShareGroupMigrationChecks(BaseMigrationChecks):
|
||||
self.cgsnapshot_id, member['cgsnapshot_id'])
|
||||
self.test_case.assertIn('share_type_id', member)
|
||||
self.test_case.assertEqual(self.share_type_id, member['share_type_id'])
|
||||
|
||||
|
||||
@map_to_migration('927920b37453')
|
||||
class ShareGroupSnapshotMemberNewProviderLocationColumnChecks(
|
||||
BaseMigrationChecks):
|
||||
table_name = 'share_group_snapshot_members'
|
||||
share_group_type_id = uuidutils.generate_uuid()
|
||||
share_group_id = uuidutils.generate_uuid()
|
||||
share_id = uuidutils.generate_uuid()
|
||||
share_instance_id = uuidutils.generate_uuid()
|
||||
share_group_snapshot_id = uuidutils.generate_uuid()
|
||||
share_group_snapshot_member_id = uuidutils.generate_uuid()
|
||||
|
||||
def setup_upgrade_data(self, engine):
|
||||
# Setup share group type
|
||||
sgt_data = {
|
||||
'id': self.share_group_type_id,
|
||||
'name': uuidutils.generate_uuid(),
|
||||
}
|
||||
sgt_table = utils.load_table('share_group_types', engine)
|
||||
engine.execute(sgt_table.insert(sgt_data))
|
||||
|
||||
# Setup share group
|
||||
sg_data = {
|
||||
'id': self.share_group_id,
|
||||
'project_id': 'fake_project_id',
|
||||
'user_id': 'fake_user_id',
|
||||
'share_group_type_id': self.share_group_type_id,
|
||||
}
|
||||
sg_table = utils.load_table('share_groups', engine)
|
||||
engine.execute(sg_table.insert(sg_data))
|
||||
|
||||
# Setup shares
|
||||
share_data = {
|
||||
'id': self.share_id,
|
||||
'share_group_id': self.share_group_id,
|
||||
}
|
||||
s_table = utils.load_table('shares', engine)
|
||||
engine.execute(s_table.insert(share_data))
|
||||
|
||||
# Setup share instances
|
||||
share_instance_data = {
|
||||
'id': self.share_instance_id,
|
||||
'share_id': share_data['id'],
|
||||
'cast_rules_to_readonly': False,
|
||||
}
|
||||
si_table = utils.load_table('share_instances', engine)
|
||||
engine.execute(si_table.insert(share_instance_data))
|
||||
|
||||
# Setup share group snapshot
|
||||
sgs_data = {
|
||||
'id': self.share_group_snapshot_id,
|
||||
'share_group_id': self.share_group_id,
|
||||
'project_id': 'fake_project_id',
|
||||
'user_id': 'fake_user_id',
|
||||
}
|
||||
sgs_table = utils.load_table('share_group_snapshots', engine)
|
||||
engine.execute(sgs_table.insert(sgs_data))
|
||||
|
||||
# Setup share group snapshot member
|
||||
sgsm_data = {
|
||||
'id': self.share_group_snapshot_member_id,
|
||||
'share_group_snapshot_id': self.share_group_snapshot_id,
|
||||
'share_id': self.share_id,
|
||||
'share_instance_id': self.share_instance_id,
|
||||
'project_id': 'fake_project_id',
|
||||
'user_id': 'fake_user_id',
|
||||
}
|
||||
sgsm_table = utils.load_table(self.table_name, engine)
|
||||
engine.execute(sgsm_table.insert(sgsm_data))
|
||||
|
||||
def check_upgrade(self, engine, data):
|
||||
sgsm_table = utils.load_table(self.table_name, engine)
|
||||
db_result = engine.execute(sgsm_table.select().where(
|
||||
sgsm_table.c.id == self.share_group_snapshot_member_id))
|
||||
self.test_case.assertEqual(1, db_result.rowcount)
|
||||
for sgsm in db_result:
|
||||
self.test_case.assertTrue(hasattr(sgsm, 'provider_location'))
|
||||
|
||||
# Check that we can write string data to the new field
|
||||
engine.execute(sgsm_table.update().where(
|
||||
sgsm_table.c.id == self.share_group_snapshot_member_id,
|
||||
).values({
|
||||
'provider_location': ('z' * 255),
|
||||
}))
|
||||
|
||||
def check_downgrade(self, engine):
|
||||
sgsm_table = utils.load_table(self.table_name, engine)
|
||||
db_result = engine.execute(sgsm_table.select().where(
|
||||
sgsm_table.c.id == self.share_group_snapshot_member_id))
|
||||
self.test_case.assertEqual(1, db_result.rowcount)
|
||||
for sgsm in db_result:
|
||||
self.test_case.assertFalse(hasattr(sgsm, 'provider_location'))
|
||||
|
@ -239,6 +239,9 @@ class DummyDriver(driver.ShareDriver):
|
||||
}
|
||||
)
|
||||
return {
|
||||
'fake_key1': 'fake_value1',
|
||||
'fake_key2': 'fake_value2',
|
||||
'fake_key3': 'fake_value3',
|
||||
"provider_location": mountpoint,
|
||||
"export_locations": self._generate_export_locations(
|
||||
mountpoint, share_server=share_server)
|
||||
@ -257,6 +260,7 @@ class DummyDriver(driver.ShareDriver):
|
||||
@slow_me_down
|
||||
def delete_snapshot(self, context, snapshot, share_server=None):
|
||||
"""Is called to remove snapshot."""
|
||||
LOG.debug('Deleting snapshot with following data: %s', snapshot)
|
||||
self.private_storage.delete(snapshot["id"])
|
||||
|
||||
@slow_me_down
|
||||
|
@ -806,16 +806,28 @@ class ShareDriverTestCase(test.TestCase):
|
||||
|
||||
def test_create_share_group_snapshot(self):
|
||||
fake_snap_member_1 = {
|
||||
'share_group_snapshot_id': 'fake_sg_snap_id',
|
||||
'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',
|
||||
'share_id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'status': 'bar',
|
||||
'share_id': 'a3ebdba5-b4e1-46c8-a0ea-a9ac8daf5296',
|
||||
'share_group_snapshot_id': 'fake_share_group_snapshot_id',
|
||||
'share_instance_id': 'fake_share_instance_id_1',
|
||||
'provider_location': 'should_not_be_used_1',
|
||||
'share': {
|
||||
'id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'size': 3,
|
||||
'share_proto': 'fake_share_proto',
|
||||
},
|
||||
}
|
||||
fake_snap_member_2 = {
|
||||
'share_group_snapshot_id': 'fake_sg_snap_id',
|
||||
'id': '1e010dfe-545b-432d-ab95-4ef03cd82f89',
|
||||
'share_id': 'a3ebdba5-b4e1-46c8-a0ea-a9ac8daf5296',
|
||||
'status': 'foo',
|
||||
'share_group_snapshot_id': 'fake_share_group_snapshot_id',
|
||||
'share_instance_id': 'fake_share_instance_id_2',
|
||||
'provider_location': 'should_not_be_used_2',
|
||||
'share': {
|
||||
'id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'size': '2',
|
||||
'share_proto': 'fake_share_proto',
|
||||
},
|
||||
}
|
||||
fake_snap_dict = {
|
||||
'status': 'available',
|
||||
@ -832,7 +844,10 @@ class ShareDriverTestCase(test.TestCase):
|
||||
}
|
||||
share_driver = self._instantiate_share_driver(None, False)
|
||||
share_driver._stats['share_group_snapshot_support'] = True
|
||||
mock_create_snap = self.mock_object(share_driver, 'create_snapshot')
|
||||
mock_create_snap = self.mock_object(
|
||||
share_driver, 'create_snapshot',
|
||||
mock.Mock(side_effect=lambda *args, **kwargs: {
|
||||
'foo_k': 'foo_v', 'bar_k': 'bar_v_%s' % args[1]['id']}))
|
||||
|
||||
share_group_snapshot_update, member_update_list = (
|
||||
share_driver.create_share_group_snapshot(
|
||||
@ -841,32 +856,50 @@ class ShareDriverTestCase(test.TestCase):
|
||||
mock_create_snap.assert_has_calls([
|
||||
mock.call(
|
||||
'fake_context',
|
||||
{'id': fake_snap_member_1['id'],
|
||||
'share_id': fake_snap_member_1['share_id'],
|
||||
'snapshot_id': fake_snap_member_1['share_group_snapshot_id']},
|
||||
share_server=None),
|
||||
mock.call(
|
||||
'fake_context',
|
||||
{'id': fake_snap_member_2['id'],
|
||||
'share_id': fake_snap_member_2['share_id'],
|
||||
'snapshot_id': fake_snap_member_2['share_group_snapshot_id']},
|
||||
share_server=None),
|
||||
{'snapshot_id': member['share_group_snapshot_id'],
|
||||
'share_id': member['share_id'],
|
||||
'share_instance_id': member['share']['id'],
|
||||
'id': member['id'],
|
||||
'share': member['share'],
|
||||
'size': member['share']['size'],
|
||||
'share_size': member['share']['size'],
|
||||
'share_proto': member['share']['share_proto'],
|
||||
'provider_location': None},
|
||||
share_server=None)
|
||||
for member in (fake_snap_member_1, fake_snap_member_2)
|
||||
])
|
||||
self.assertIsNone(share_group_snapshot_update)
|
||||
self.assertIsNone(member_update_list)
|
||||
self.assertEqual(
|
||||
[{'id': member['id'], 'foo_k': 'foo_v',
|
||||
'bar_k': 'bar_v_%s' % member['id']}
|
||||
for member in (fake_snap_member_1, fake_snap_member_2)],
|
||||
member_update_list,
|
||||
)
|
||||
|
||||
def test_create_share_group_snapshot_failed_snapshot(self):
|
||||
fake_snap_member_1 = {
|
||||
'share_group_snapshot_id': 'fake_sg_snap_id',
|
||||
'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',
|
||||
'share_id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'status': 'bar',
|
||||
'share_id': 'a3ebdba5-b4e1-46c8-a0ea-a9ac8daf5296',
|
||||
'share_group_snapshot_id': 'fake_share_group_snapshot_id',
|
||||
'share_instance_id': 'fake_share_instance_id_1',
|
||||
'provider_location': 'should_not_be_used_1',
|
||||
'share': {
|
||||
'id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'size': 3,
|
||||
'share_proto': 'fake_share_proto',
|
||||
},
|
||||
}
|
||||
fake_snap_member_2 = {
|
||||
'share_group_snapshot_id': 'fake_sg_snap_id',
|
||||
'id': '1e010dfe-545b-432d-ab95-4ef03cd82f89',
|
||||
'share_id': 'a3ebdba5-b4e1-46c8-a0ea-a9ac8daf5296',
|
||||
'status': 'foo',
|
||||
'share_group_snapshot_id': 'fake_share_group_snapshot_id',
|
||||
'share_instance_id': 'fake_share_instance_id_2',
|
||||
'provider_location': 'should_not_be_used_2',
|
||||
'share': {
|
||||
'id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'size': '2',
|
||||
'share_proto': 'fake_share_proto',
|
||||
},
|
||||
}
|
||||
fake_snap_dict = {
|
||||
'status': 'available',
|
||||
@ -896,20 +929,30 @@ class ShareDriverTestCase(test.TestCase):
|
||||
'fake_context', fake_snap_dict)
|
||||
|
||||
fake_snap_member_1_expected = {
|
||||
'id': fake_snap_member_1['id'],
|
||||
'share_id': fake_snap_member_1['share_id'],
|
||||
'snapshot_id': fake_snap_member_1['share_group_snapshot_id'],
|
||||
'share_id': fake_snap_member_1['share_id'],
|
||||
'share_instance_id': fake_snap_member_1['share']['id'],
|
||||
'id': fake_snap_member_1['id'],
|
||||
'share': fake_snap_member_1['share'],
|
||||
'size': fake_snap_member_1['share']['size'],
|
||||
'share_size': fake_snap_member_1['share']['size'],
|
||||
'share_proto': fake_snap_member_1['share']['share_proto'],
|
||||
'provider_location': None,
|
||||
}
|
||||
mock_create_snap.assert_has_calls([
|
||||
mock.call(
|
||||
'fake_context', fake_snap_member_1_expected, share_server=None,
|
||||
),
|
||||
mock.call(
|
||||
'fake_context',
|
||||
{'id': fake_snap_member_2['id'],
|
||||
'share_id': fake_snap_member_2['share_id'],
|
||||
'snapshot_id': fake_snap_member_2['share_group_snapshot_id']},
|
||||
share_server=None),
|
||||
{'snapshot_id': member['share_group_snapshot_id'],
|
||||
'share_id': member['share_id'],
|
||||
'share_instance_id': member['share']['id'],
|
||||
'id': member['id'],
|
||||
'share': member['share'],
|
||||
'size': member['share']['size'],
|
||||
'share_size': member['share']['size'],
|
||||
'share_proto': member['share']['share_proto'],
|
||||
'provider_location': None},
|
||||
share_server=None)
|
||||
for member in (fake_snap_member_1, fake_snap_member_2)
|
||||
])
|
||||
mock_delete_snap.assert_called_with(
|
||||
'fake_context', fake_snap_member_1_expected, share_server=None)
|
||||
@ -975,11 +1018,27 @@ class ShareDriverTestCase(test.TestCase):
|
||||
def test_delete_share_group_snapshot(self):
|
||||
fake_snap_member_1 = {
|
||||
'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',
|
||||
'share_id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2'
|
||||
'share_id': 'a3ebdba5-b4e1-46c8-a0ea-a9ac8daf5296',
|
||||
'share_group_snapshot_id': 'fake_share_group_snapshot_id',
|
||||
'share_instance_id': 'fake_share_instance_id_1',
|
||||
'provider_location': 'fake_provider_location_2',
|
||||
'share': {
|
||||
'id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'size': 3,
|
||||
'share_proto': 'fake_share_proto',
|
||||
},
|
||||
}
|
||||
fake_snap_member_2 = {
|
||||
'id': '1e010dfe-545b-432d-ab95-4ef03cd82f89',
|
||||
'share_id': 'a3ebdba5-b4e1-46c8-a0ea-a9ac8daf5296'
|
||||
'share_id': 'a3ebdba5-b4e1-46c8-a0ea-a9ac8daf5296',
|
||||
'share_group_snapshot_id': 'fake_share_group_snapshot_id',
|
||||
'share_instance_id': 'fake_share_instance_id_2',
|
||||
'provider_location': 'fake_provider_location_2',
|
||||
'share': {
|
||||
'id': '420f978b-dbf6-4b3c-92fe-f5b17a0bb5e2',
|
||||
'size': '2',
|
||||
'share_proto': 'fake_share_proto',
|
||||
},
|
||||
}
|
||||
fake_snap_dict = {
|
||||
'status': 'available',
|
||||
@ -1004,8 +1063,19 @@ class ShareDriverTestCase(test.TestCase):
|
||||
'fake_context', fake_snap_dict))
|
||||
|
||||
mock_delete_snap.assert_has_calls([
|
||||
mock.call('fake_context', fake_snap_member_1, share_server=None),
|
||||
mock.call('fake_context', fake_snap_member_2, share_server=None),
|
||||
mock.call(
|
||||
'fake_context',
|
||||
{'snapshot_id': member['share_group_snapshot_id'],
|
||||
'share_id': member['share_id'],
|
||||
'share_instance_id': member['share']['id'],
|
||||
'id': member['id'],
|
||||
'share': member['share'],
|
||||
'size': member['share']['size'],
|
||||
'share_size': member['share']['size'],
|
||||
'share_proto': member['share']['share_proto'],
|
||||
'provider_location': member['provider_location']},
|
||||
share_server=None)
|
||||
for member in (fake_snap_member_1, fake_snap_member_2)
|
||||
])
|
||||
self.assertIsNone(share_group_snapshot_update)
|
||||
self.assertIsNone(member_update_list)
|
||||
|
@ -3580,7 +3580,7 @@ class ShareManagerTestCase(test.TestCase):
|
||||
|
||||
mock_sg_snap_update.assert_called_once_with(
|
||||
mock.ANY, fake_snap['id'],
|
||||
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
|
||||
{'status': constants.STATUS_AVAILABLE, 'updated_at': mock.ANY})
|
||||
|
||||
def test_create_share_group_snapshot_with_update(self):
|
||||
fake_snap = {'id': 'fake_snap_id', 'share_group': {},
|
||||
@ -3600,39 +3600,96 @@ class ShareManagerTestCase(test.TestCase):
|
||||
mock.ANY, 'fake_snap_id', {'foo': 'bar'})
|
||||
self.share_manager.db.share_group_snapshot_update.assert_any_call(
|
||||
mock.ANY, fake_snap['id'],
|
||||
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
|
||||
{'status': constants.STATUS_AVAILABLE, 'updated_at': mock.ANY})
|
||||
|
||||
def test_create_share_group_snapshot_with_member_update(self):
|
||||
fake_member = {'id': 'fake_member_id', 'share_instance_id': 'blah'}
|
||||
fake_member_update = {'id': 'fake_member_id', 'foo': 'bar'}
|
||||
fake_snap = {'id': 'fake_snap_id', 'share_group': {},
|
||||
'share_group_snapshot_members': [fake_member]}
|
||||
fake_member1 = {'id': 'fake_member_id_1', 'share_instance_id': 'si_1'}
|
||||
fake_member2 = {'id': 'fake_member_id_2', 'share_instance_id': 'si_2'}
|
||||
fake_member3 = {'id': 'fake_member_id_3', 'share_instance_id': 'si_3'}
|
||||
fake_member_update1 = {
|
||||
'id': fake_member1['id'],
|
||||
'provider_location': 'fake_provider_location_1',
|
||||
'size': 13,
|
||||
'export_locations': ['fake_el_1_1', 'fake_el_1_2'],
|
||||
'should_not_be_used_k1': 'should_not_be_used_v1',
|
||||
}
|
||||
fake_member_update2 = {
|
||||
'id': fake_member2['id'],
|
||||
'provider_location': 'fake_provider_location_2',
|
||||
'size': 31,
|
||||
'export_locations': ['fake_el_2_1', 'fake_el_2_2'],
|
||||
'status': 'fake_status_for_update',
|
||||
'should_not_be_used_k2': 'should_not_be_used_k2',
|
||||
}
|
||||
fake_member_update3 = {
|
||||
'provider_location': 'fake_provider_location_3',
|
||||
'size': 42,
|
||||
'export_locations': ['fake_el_3_1', 'fake_el_3_2'],
|
||||
'should_not_be_used_k3': 'should_not_be_used_k3',
|
||||
}
|
||||
expected_member_update1 = {
|
||||
'id': fake_member_update1['id'],
|
||||
'provider_location': fake_member_update1['provider_location'],
|
||||
'size': fake_member_update1['size'],
|
||||
}
|
||||
expected_member_update2 = {
|
||||
'id': fake_member_update2['id'],
|
||||
'provider_location': fake_member_update2['provider_location'],
|
||||
'size': fake_member_update2['size'],
|
||||
'status': fake_member_update2['status'],
|
||||
}
|
||||
fake_snap = {
|
||||
'id': 'fake_snap_id',
|
||||
'share_group': {},
|
||||
'share_group_snapshot_members': [
|
||||
fake_member1, fake_member2, fake_member3],
|
||||
}
|
||||
self.mock_object(
|
||||
self.share_manager.db, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=fake_snap))
|
||||
self.mock_object(
|
||||
mock_sg_snapshot_update = self.mock_object(
|
||||
self.share_manager.db, 'share_group_snapshot_update',
|
||||
mock.Mock(return_value=fake_snap))
|
||||
self.mock_object(
|
||||
mock_sg_snapshot_member_update = self.mock_object(
|
||||
self.share_manager.db, 'share_group_snapshot_member_update')
|
||||
self.mock_object(
|
||||
self.share_manager.db, 'share_instance_get',
|
||||
mock.Mock(return_value={'id': 'blah'}))
|
||||
self.mock_object(
|
||||
timeutils, 'utcnow', mock.Mock(side_effect=range(1, 10)))
|
||||
mock_driver_create_sg_snapshot = self.mock_object(
|
||||
self.share_manager.driver, 'create_share_group_snapshot',
|
||||
mock.Mock(return_value=(None, [fake_member_update])))
|
||||
mock.Mock(return_value=(
|
||||
None, [fake_member_update1, fake_member_update2,
|
||||
fake_member_update3])))
|
||||
|
||||
self.share_manager.create_share_group_snapshot(
|
||||
self.context, fake_snap['id'])
|
||||
|
||||
self.share_manager.db.share_group_snapshot_update.assert_any_call(
|
||||
mock_driver_create_sg_snapshot.assert_called_once_with(
|
||||
utils.IsAMatcher(context.RequestContext),
|
||||
fake_snap, share_server=None)
|
||||
mock_sg_snapshot_update.assert_called_once_with(
|
||||
mock.ANY, fake_snap['id'],
|
||||
{'share_group_snapshot_members': [fake_member_update]})
|
||||
self.share_manager.db.share_group_snapshot_update.assert_any_call(
|
||||
mock.ANY, fake_snap['id'],
|
||||
{'status': constants.STATUS_AVAILABLE, 'created_at': mock.ANY})
|
||||
self.assertTrue(
|
||||
self.share_manager.db.share_group_snapshot_member_update.called)
|
||||
{'status': constants.STATUS_AVAILABLE, 'updated_at': mock.ANY})
|
||||
mock_sg_snapshot_member_update.assert_has_calls([
|
||||
mock.call(
|
||||
utils.IsAMatcher(context.RequestContext),
|
||||
expected_member_update1['id'],
|
||||
{'provider_location': expected_member_update1[
|
||||
'provider_location'],
|
||||
'size': expected_member_update1['size'],
|
||||
'updated_at': 1,
|
||||
'status': manager.constants.STATUS_AVAILABLE}),
|
||||
mock.call(
|
||||
utils.IsAMatcher(context.RequestContext),
|
||||
expected_member_update2['id'],
|
||||
{'provider_location': expected_member_update2[
|
||||
'provider_location'],
|
||||
'size': expected_member_update2['size'],
|
||||
'updated_at': 1,
|
||||
'status': expected_member_update2['status']}),
|
||||
])
|
||||
|
||||
def test_create_group_snapshot_with_error(self):
|
||||
fake_snap = {'id': 'fake_snap_id', 'share_group': {},
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
fixes:
|
||||
- Fixed default approach for creating share group snapshots that uses
|
||||
common share driver interface by making proper call of this method.
|
||||
Before, some drivers that were depending on some specific data
|
||||
from 'snapshot' object were failing not being able to get these data.
|
Loading…
Reference in New Issue
Block a user