cinder/cinder/volume/drivers/coprhd/helpers/snapshot.py

258 lines
9.3 KiB
Python

# Copyright (c) 2016 EMC Corporation
# All Rights Reserved.
#
# 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.
import oslo_serialization
from cinder.i18n import _
from cinder.volume.drivers.coprhd.helpers import commoncoprhdapi as common
from cinder.volume.drivers.coprhd.helpers import consistencygroup
from cinder.volume.drivers.coprhd.helpers import volume
class Snapshot(common.CoprHDResource):
# Commonly used URIs for the 'Snapshot' module
URI_SNAPSHOTS = '/{0}/snapshots/{1}'
URI_BLOCK_SNAPSHOTS = '/block/snapshots/{0}'
URI_SEARCH_SNAPSHOT_BY_TAG = '/block/snapshots/search?tag={0}'
URI_SNAPSHOT_LIST = '/{0}/{1}/{2}/protection/snapshots'
URI_SNAPSHOT_TASKS_BY_OPID = '/vdc/tasks/{0}'
URI_RESOURCE_DEACTIVATE = '{0}/deactivate'
URI_CONSISTENCY_GROUP = "/block/consistency-groups"
URI_CONSISTENCY_GROUPS_SNAPSHOT_INSTANCE = (
URI_CONSISTENCY_GROUP + "/{0}/protection/snapshots/{1}")
URI_CONSISTENCY_GROUPS_SNAPSHOT_DEACTIVATE = (
URI_CONSISTENCY_GROUPS_SNAPSHOT_INSTANCE + "/deactivate")
URI_BLOCK_SNAPSHOTS_TAG = URI_BLOCK_SNAPSHOTS + '/tags'
VOLUMES = 'volumes'
CG = 'consistency-groups'
BLOCK = 'block'
timeout = 300
def snapshot_list_uri(self, otype, otypename, ouri):
"""Makes REST API call to list snapshots under a volume.
:param otype: block
:param otypename: either volume or consistency-group should be
provided
:param ouri: uri of volume or consistency-group
:returns: list of snapshots
"""
(s, h) = common.service_json_request(
self.ipaddr, self.port,
"GET",
Snapshot.URI_SNAPSHOT_LIST.format(otype, otypename, ouri), None)
o = common.json_decode(s)
return o['snapshot']
def snapshot_show_uri(self, otype, resource_uri, suri):
"""Retrieves snapshot details based on snapshot Name or Label.
:param otype: block
:param suri: uri of the Snapshot.
:param resource_uri: uri of the source resource
:returns: Snapshot details in JSON response payload
"""
if(resource_uri is not None and
resource_uri.find('BlockConsistencyGroup') > 0):
(s, h) = common.service_json_request(
self.ipaddr, self.port,
"GET",
Snapshot.URI_CONSISTENCY_GROUPS_SNAPSHOT_INSTANCE.format(
resource_uri,
suri),
None)
else:
(s, h) = common.service_json_request(
self.ipaddr, self.port,
"GET",
Snapshot.URI_SNAPSHOTS.format(otype, suri), None)
return common.json_decode(s)
def snapshot_query(self, storageres_type,
storageres_typename, resuri, snapshot_name):
if resuri is not None:
uris = self.snapshot_list_uri(
storageres_type,
storageres_typename,
resuri)
for uri in uris:
snapshot = self.snapshot_show_uri(
storageres_type,
resuri,
uri['id'])
if (False == common.get_node_value(snapshot, 'inactive') and
snapshot['name'] == snapshot_name):
return snapshot['id']
raise common.CoprHdError(
common.CoprHdError.SOS_FAILURE_ERR,
(_("snapshot with the name: "
"%s Not Found") % snapshot_name))
def storage_resource_query(self,
storageres_type,
volume_name,
cg_name,
project,
tenant):
resourcepath = "/" + project
if tenant is not None:
resourcepath = tenant + resourcepath
resUri = None
resourceObj = None
if Snapshot.BLOCK == storageres_type and volume_name is not None:
resourceObj = volume.Volume(self.ipaddr, self.port)
resUri = resourceObj.volume_query(resourcepath, volume_name)
elif Snapshot.BLOCK == storageres_type and cg_name is not None:
resourceObj = consistencygroup.ConsistencyGroup(
self.ipaddr,
self.port)
resUri = resourceObj.consistencygroup_query(
cg_name,
project,
tenant)
else:
resourceObj = None
return resUri
def snapshot_create(self, otype, typename, ouri,
snaplabel, inactive, sync,
readonly=False, synctimeout=0):
"""New snapshot is created, for a given volume.
:param otype: block type should be provided
:param typename: either volume or consistency-groups should
be provided
:param ouri: uri of volume
:param snaplabel: name of the snapshot
:param inactive: if true, the snapshot will not activate the
synchronization between source and target volumes
:param sync: synchronous request
:param synctimeout: Query for task status for 'synctimeout' secs.
If the task doesn't complete in synctimeout secs,
an exception is thrown
"""
# check snapshot is already exist
is_snapshot_exist = True
try:
self.snapshot_query(otype, typename, ouri, snaplabel)
except common.CoprHdError as e:
if e.err_code == common.CoprHdError.NOT_FOUND_ERR:
is_snapshot_exist = False
else:
raise
if is_snapshot_exist:
raise common.CoprHdError(
common.CoprHdError.ENTRY_ALREADY_EXISTS_ERR,
(_("Snapshot with name %(snaplabel)s"
" already exists under %(typename)s") %
{'snaplabel': snaplabel,
'typename': typename
}))
parms = {
'name': snaplabel,
# if true, the snapshot will not activate the synchronization
# between source and target volumes
'create_inactive': inactive
}
if readonly is True:
parms['read_only'] = readonly
body = oslo_serialization.jsonutils.dumps(parms)
# REST api call
(s, h) = common.service_json_request(
self.ipaddr, self.port,
"POST",
Snapshot.URI_SNAPSHOT_LIST.format(otype, typename, ouri), body)
o = common.json_decode(s)
task = o["task"][0]
if sync:
return (
common.block_until_complete(
otype,
task['resource']['id'],
task["id"], self.ipaddr, self.port, synctimeout)
)
else:
return o
def snapshot_delete_uri(self, otype, resource_uri,
suri, sync, synctimeout=0):
"""Delete a snapshot by uri.
:param otype: block
:param resource_uri: uri of the source resource
:param suri: Uri of the Snapshot
:param sync: To perform operation synchronously
:param synctimeout: Query for task status for 'synctimeout' secs. If
the task doesn't complete in synctimeout secs,
an exception is thrown
"""
s = None
if resource_uri.find("Volume") > 0:
(s, h) = common.service_json_request(
self.ipaddr, self.port,
"POST",
Snapshot.URI_RESOURCE_DEACTIVATE.format(
Snapshot.URI_BLOCK_SNAPSHOTS.format(suri)),
None)
elif resource_uri.find("BlockConsistencyGroup") > 0:
(s, h) = common.service_json_request(
self.ipaddr, self.port,
"POST",
Snapshot.URI_CONSISTENCY_GROUPS_SNAPSHOT_DEACTIVATE.format(
resource_uri,
suri),
None)
o = common.json_decode(s)
task = o["task"][0]
if sync:
return (
common.block_until_complete(
otype,
task['resource']['id'],
task["id"], self.ipaddr, self.port, synctimeout)
)
else:
return o
def snapshot_delete(self, storageres_type,
storageres_typename, resource_uri,
name, sync, synctimeout=0):
snapshotUri = self.snapshot_query(
storageres_type,
storageres_typename,
resource_uri,
name)
self.snapshot_delete_uri(
storageres_type,
resource_uri,
snapshotUri,
sync, synctimeout)