97e72e40d0
merged from Ifb5cb05b9cc2b8758d5a8e34f7792470a73d7c40 PEP-0274 introduced dict comprehensions to replace dict constructor with a sequence of length-2 sequences, these are benefits copied from [1]: The dictionary constructor approach has two distinct disadvantages from the proposed syntax though. First, it isn't as legible as a dict comprehension. Second, it forces the programmer to create an in-core list object first, which could be expensive. Nova dropped python 2.6 support, we can leverage this now. There is deep dive about PEP-0274[2] and basic tests about performance[3]. Note: This commit doesn't handle dict constructor with kwagrs. This commit also adds a hacking rule. [1]http://legacy.python.org/dev/peps/pep-0274/ [2]http://doughellmann.com/2012/11/12/the-performance-impact-of-using-dict-instead-of-in-cpython-2-7-2.html [3]http://paste.openstack.org/show/154798/ Change-Id: I1bc53e335b6c291da5c54f067f9fdfd5da6b2902
141 lines
5.1 KiB
Python
141 lines
5.1 KiB
Python
# Copyright 2014
|
|
# The Cloudscaling Group, Inc.
|
|
#
|
|
# 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 cinderclient import exceptions as cinder_exception
|
|
|
|
from ec2api.api import clients
|
|
from ec2api.api import common
|
|
from ec2api.api import ec2utils
|
|
from ec2api.db import api as db_api
|
|
from ec2api import exception
|
|
from ec2api.i18n import _
|
|
|
|
|
|
"""Snapshot related API implementation
|
|
"""
|
|
|
|
|
|
Validator = common.Validator
|
|
|
|
|
|
def create_snapshot(context, volume_id, description=None):
|
|
volume = ec2utils.get_db_item(context, volume_id)
|
|
cinder = clients.cinder(context)
|
|
os_volume = cinder.volumes.get(volume['os_id'])
|
|
# NOTE(ft): Easy fix to allow snapshot creation in statuses other than
|
|
# AVAILABLE without cinder modifications. Potential race condition
|
|
# though. Seems arguably non-fatal.
|
|
if os_volume.status not in ['available', 'in-use',
|
|
'attaching', 'detaching']:
|
|
msg = (_("'%s' is not in a state where snapshots are allowed.") %
|
|
volume_id)
|
|
raise exception.IncorrectState(reason=msg)
|
|
with common.OnCrashCleaner() as cleaner:
|
|
os_snapshot = cinder.volume_snapshots.create(
|
|
os_volume.id, force=True,
|
|
display_description=description)
|
|
cleaner.addCleanup(os_snapshot.delete)
|
|
snapshot = db_api.add_item(context, 'snap', {'os_id': os_snapshot.id})
|
|
cleaner.addCleanup(db_api.delete_item, context, snapshot['id'])
|
|
os_snapshot.update(display_name=snapshot['id'])
|
|
|
|
return _format_snapshot(context, snapshot, os_snapshot,
|
|
volume_id=volume_id)
|
|
|
|
|
|
def delete_snapshot(context, snapshot_id):
|
|
snapshot = ec2utils.get_db_item(context, snapshot_id)
|
|
cinder = clients.cinder(context)
|
|
try:
|
|
cinder.volume_snapshots.delete(snapshot['os_id'])
|
|
except cinder_exception.NotFound:
|
|
pass
|
|
# NOTE(andrey-mp) Don't delete item from DB until it disappears from Cloud
|
|
# It will be deleted by describer in the future
|
|
return True
|
|
|
|
|
|
class SnapshotDescriber(common.TaggableItemsDescriber):
|
|
|
|
KIND = 'snap'
|
|
FILTER_MAP = {'description': 'description',
|
|
'owner-id': 'ownerId',
|
|
'progress': 'progress',
|
|
'snapshot-id': 'snapshotId',
|
|
'start-time': 'startTime',
|
|
'status': 'status',
|
|
'volume-id': 'volumeId',
|
|
'volume-size': 'volumeSize'}
|
|
|
|
def format(self, snapshot, os_snapshot):
|
|
return _format_snapshot(self.context, snapshot, os_snapshot,
|
|
self.volumes)
|
|
|
|
def get_db_items(self):
|
|
self.volumes = {vol['os_id']: vol
|
|
for vol in db_api.get_items(self.context, 'vol')}
|
|
return super(SnapshotDescriber, self).get_db_items()
|
|
|
|
def get_os_items(self):
|
|
return clients.cinder(self.context).volume_snapshots.list()
|
|
|
|
def get_name(self, os_item):
|
|
return ''
|
|
|
|
|
|
def describe_snapshots(context, snapshot_id=None, owner=None,
|
|
restorable_by=None, filter=None):
|
|
formatted_snapshots = SnapshotDescriber().describe(
|
|
context, ids=snapshot_id, filter=filter)
|
|
return {'snapshotSet': formatted_snapshots}
|
|
|
|
|
|
def _format_snapshot(context, snapshot, os_snapshot, volumes={},
|
|
volume_id=None):
|
|
# NOTE(mikal): this is just a set of strings in cinder. If they
|
|
# implement an enum, then we should move this code to use it. The
|
|
# valid ec2 statuses are "pending", "completed", and "error".
|
|
status_map = {'new': 'pending',
|
|
'creating': 'pending',
|
|
'available': 'completed',
|
|
'active': 'completed',
|
|
'deleting': 'pending',
|
|
'deleted': None,
|
|
'error': 'error'}
|
|
|
|
mapped_status = status_map.get(os_snapshot.status, os_snapshot.status)
|
|
if not mapped_status:
|
|
return None
|
|
|
|
if not volume_id and os_snapshot.volume_id:
|
|
volume = ec2utils.get_db_item_by_os_id(
|
|
context, 'vol', os_snapshot.volume_id, volumes)
|
|
volume_id = volume['id']
|
|
|
|
# NOTE(andrey-mp): ownerId and progress are empty in just created snapshot
|
|
ownerId = os_snapshot.project_id
|
|
if not ownerId:
|
|
ownerId = context.project_id
|
|
progress = os_snapshot.progress
|
|
if not progress:
|
|
progress = '0%'
|
|
return {'snapshotId': snapshot['id'],
|
|
'volumeId': volume_id,
|
|
'status': mapped_status,
|
|
'startTime': os_snapshot.created_at,
|
|
'progress': progress,
|
|
'ownerId': ownerId,
|
|
'volumeSize': os_snapshot.size,
|
|
'description': os_snapshot.display_description}
|