cinder/cinder/tests/unit/fake_snapshot.py
Andrey Pavlov c933c08c89 Avoid race condition at snapshot deletion stage
Snapshot`s list method can raise SnapshotNotFound exception.
It happens because of race condition:
1. List method gets all snapshots from DB.
2. At the same time one of the snapshots is being deleted from DB.
3. List method gets snapshot metadata from DB and checks
   that snapshot exists in DB and raises the exception.

This patchset changes behaviour of getting snapshot metadata from DB.
Code now gets metadata from db_snapshot object that was queried
by joined query from DB instead of second query for each snapshot
for metadata.

And I removed checking of snapshot existence for getting
metadata for private method because all public methods already have
such decorator. Using second decorator will slow public method.

Change-Id: I7f743638d9be4c01e18315a3459aecd2b3e9fd87
Closes-Bug: #1462453
2015-07-02 15:50:01 +03:00

54 lines
1.8 KiB
Python

# Copyright 2015 SimpliVity Corp.
#
# 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 oslo_versionedobjects import fields
from cinder.objects import snapshot
def fake_db_snapshot(**updates):
db_snapshot = {
'id': 1,
'volume_id': 'fake_id',
'status': "creating",
'progress': '0%',
'volume_size': 1,
'display_name': 'fake_name',
'display_description': 'fake_description',
'metadata': {},
'snapshot_metadata': [],
}
for name, field in snapshot.Snapshot.fields.items():
if name in db_snapshot:
continue
if field.nullable:
db_snapshot[name] = None
elif field.default != fields.UnspecifiedDefault:
db_snapshot[name] = field.default
else:
raise Exception('fake_db_snapshot needs help with %s' % name)
if updates:
db_snapshot.update(updates)
return db_snapshot
def fake_snapshot_obj(context, **updates):
expected_attrs = updates.pop('expected_attrs', None)
return snapshot.Snapshot._from_db_object(context, snapshot.Snapshot(),
fake_db_snapshot(**updates),
expected_attrs=expected_attrs)