"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "cinder/volume/drivers/solidfire.py" between
cinder-15.4.1.tar.gz and cinder-15.5.0.tar.gz

About: OpenStack Cinder (Core Service: Block Storage) provides persistent block storage to running instances. Its pluggable driver architecture facilitates the creation and management of block storage devices.
The "Train" series (maintained release).

solidfire.py  (cinder-15.4.1):solidfire.py  (cinder-15.5.0)
skipping to change at line 27 skipping to change at line 27
import json import json
import math import math
import re import re
import socket import socket
import string import string
import time import time
import warnings import warnings
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_service import loopingcall
from oslo_utils import excutils from oslo_utils import excutils
from oslo_utils import timeutils from oslo_utils import timeutils
from oslo_utils import units from oslo_utils import units
import requests import requests
import six import six
from cinder import context from cinder import context
from cinder import exception from cinder import exception
from cinder.i18n import _ from cinder.i18n import _
from cinder import interface from cinder import interface
skipping to change at line 89 skipping to change at line 90
cfg.BoolOpt('sf_enable_vag', cfg.BoolOpt('sf_enable_vag',
default=False, default=False,
help='Utilize volume access groups on a per-tenant basis.'), help='Utilize volume access groups on a per-tenant basis.'),
cfg.StrOpt('sf_provisioning_calc', cfg.StrOpt('sf_provisioning_calc',
default='maxProvisionedSpace', default='maxProvisionedSpace',
choices=['maxProvisionedSpace', 'usedSpace'], choices=['maxProvisionedSpace', 'usedSpace'],
help='Change how SolidFire reports used space and ' help='Change how SolidFire reports used space and '
'provisioning calculations. If this parameter is set to ' 'provisioning calculations. If this parameter is set to '
'\'usedSpace\', the driver will report correct ' '\'usedSpace\', the driver will report correct '
'values as expected by Cinder ' 'values as expected by Cinder '
'thin provisioning.')] 'thin provisioning.'),
cfg.IntOpt('sf_api_request_timeout',
default=30,
min=30,
help='Sets time in seconds to wait for an api request to '
'complete.'),
cfg.IntOpt('sf_volume_clone_timeout',
default=600,
min=60,
help='Sets time in seconds to wait for a clone of a volume or '
'snapshot to complete.'
),
cfg.IntOpt('sf_volume_create_timeout',
default=60,
min=30,
help='Sets time in seconds to wait for a create volume '
'operation to complete.')]
CONF = cfg.CONF CONF = cfg.CONF
CONF.register_opts(sf_opts, group=configuration.SHARED_CONF_GROUP) CONF.register_opts(sf_opts, group=configuration.SHARED_CONF_GROUP)
# SolidFire API Error Constants # SolidFire API Error Constants
xExceededLimit = 'xExceededLimit' xExceededLimit = 'xExceededLimit'
xAlreadyInVolumeAccessGroup = 'xAlreadyInVolumeAccessGroup' xAlreadyInVolumeAccessGroup = 'xAlreadyInVolumeAccessGroup'
xVolumeAccessGroupIDDoesNotExist = 'xVolumeAccessGroupIDDoesNotExist' xVolumeAccessGroupIDDoesNotExist = 'xVolumeAccessGroupIDDoesNotExist'
xNotInVolumeAccessGroup = 'xNotInVolumeAccessGroup' xNotInVolumeAccessGroup = 'xNotInVolumeAccessGroup'
skipping to change at line 216 skipping to change at line 234
2.0.9 - Always purge on delete volume 2.0.9 - Always purge on delete volume
2.0.10 - Add response to debug on retryable errors 2.0.10 - Add response to debug on retryable errors
2.0.11 - Add ability to failback replicating volumes 2.0.11 - Add ability to failback replicating volumes
2.0.12 - Fix bug #1744005 2.0.12 - Fix bug #1744005
2.0.14 - Fix bug #1782588 qos settings on extend 2.0.14 - Fix bug #1782588 qos settings on extend
2.0.15 - Fix bug #1834013 NetApp SolidFire replication errors 2.0.15 - Fix bug #1834013 NetApp SolidFire replication errors
2.0.16 - Add options for replication mode (Async, Sync and 2.0.16 - Add options for replication mode (Async, Sync and
SnapshotsOnly) SnapshotsOnly)
2.0.17 - Fix bug #1859653 SolidFire fails to failback when volume 2.0.17 - Fix bug #1859653 SolidFire fails to failback when volume
service is restarted service is restarted
2.0.18 - Fix bug #1896112 SolidFire Driver creates duplicate volume
when API response is lost
2.0.19 - Fix bug #1891914 fix error on cluster workload rebalancing
by adding xNotPrimary to the retryable exception list
""" """
VERSION = '2.0.17' VERSION = '2.0.19'
# ThirdPartySystems wiki page # ThirdPartySystems wiki page
CI_WIKI_NAME = "NetApp_SolidFire_CI" CI_WIKI_NAME = "NetApp_SolidFire_CI"
driver_prefix = 'solidfire' driver_prefix = 'solidfire'
sf_qos_dict = {'slow': {'minIOPS': 100, sf_qos_dict = {'slow': {'minIOPS': 100,
'maxIOPS': 200, 'maxIOPS': 200,
'burstIOPS': 200}, 'burstIOPS': 200},
'medium': {'minIOPS': 200, 'medium': {'minIOPS': 200,
skipping to change at line 254 skipping to change at line 276
'burstIOPS': 200000} 'burstIOPS': 200000}
cluster_stats = {} cluster_stats = {}
retry_exc_tuple = (SolidFireRetryableException, retry_exc_tuple = (SolidFireRetryableException,
requests.exceptions.ConnectionError) requests.exceptions.ConnectionError)
retryable_errors = ['xDBVersionMismatch', retryable_errors = ['xDBVersionMismatch',
'xMaxSnapshotsPerVolumeExceeded', 'xMaxSnapshotsPerVolumeExceeded',
'xMaxClonesPerVolumeExceeded', 'xMaxClonesPerVolumeExceeded',
'xMaxSnapshotsPerNodeExceeded', 'xMaxSnapshotsPerNodeExceeded',
'xMaxClonesPerNodeExceeded', 'xMaxClonesPerNodeExceeded',
'xSliceNotRegistered', 'xSliceNotRegistered',
'xNotReadyForIO'] 'xNotReadyForIO',
'xNotPrimary']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(SolidFireDriver, self).__init__(*args, **kwargs) super(SolidFireDriver, self).__init__(*args, **kwargs)
self.failed_over_id = kwargs.get('active_backend_id', None) self.failed_over_id = kwargs.get('active_backend_id', None)
self.replication_status = kwargs.get('replication_status', "na") self.replication_status = kwargs.get('replication_status', "na")
self.configuration.append_config_values(sf_opts) self.configuration.append_config_values(sf_opts)
self.template_account_id = None self.template_account_id = None
self.max_volumes_per_account = 1990 self.max_volumes_per_account = 1990
self.volume_map = {} self.volume_map = {}
self.cluster_pairs = [] self.cluster_pairs = []
skipping to change at line 574 skipping to change at line 597
endpoint['port'] = ( endpoint['port'] = (
kwargs.get(('port'), self.configuration.sf_api_port)) kwargs.get(('port'), self.configuration.sf_api_port))
endpoint['url'] = 'https://%s:%s' % (endpoint['mvip'], endpoint['url'] = 'https://%s:%s' % (endpoint['mvip'],
endpoint['port']) endpoint['port'])
endpoint['svip'] = kwargs.get('svip', self.configuration.sf_svip) endpoint['svip'] = kwargs.get('svip', self.configuration.sf_svip)
if not endpoint.get('mvip', None) and kwargs.get('backend_id', None): if not endpoint.get('mvip', None) and kwargs.get('backend_id', None):
endpoint['mvip'] = kwargs.get('backend_id') endpoint['mvip'] = kwargs.get('backend_id')
return endpoint return endpoint
@retry(retry_exc_tuple, tries=6) @retry(retry_exc_tuple, tries=6)
def _issue_api_request(self, method, params, version='1.0', endpoint=None): def _issue_api_request(self, method, params, version='1.0',
endpoint=None, timeout=None):
if params is None: if params is None:
params = {} params = {}
if endpoint is None: if endpoint is None:
endpoint = self.active_cluster['endpoint'] endpoint = self.active_cluster['endpoint']
if not timeout:
timeout = self.configuration.sf_api_request_timeout
payload = {'method': method, 'params': params} payload = {'method': method, 'params': params}
url = '%s/json-rpc/%s/' % (endpoint['url'], version) url = '%s/json-rpc/%s/' % (endpoint['url'], version)
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter( warnings.simplefilter(
"ignore", "ignore",
requests.packages.urllib3.exceptions.InsecureRequestWarning) requests.packages.urllib3.exceptions.InsecureRequestWarning)
req = requests.post(url, req = requests.post(url,
data=json.dumps(payload), data=json.dumps(payload),
auth=(endpoint['login'], endpoint['passwd']), auth=(endpoint['login'], endpoint['passwd']),
verify=self.verify_ssl, verify=self.verify_ssl,
timeout=30) timeout=timeout)
response = req.json() response = req.json()
req.close() req.close()
if (('error' in response) and if (('error' in response) and
(response['error']['name'] in self.retryable_errors)): (response['error']['name'] in self.retryable_errors)):
msg = ('Retryable error (%s) encountered during ' msg = ('Retryable error (%s) encountered during '
'SolidFire API call.' % response['error']['name']) 'SolidFire API call.' % response['error']['name'])
LOG.debug(msg) LOG.debug(msg)
LOG.debug("API response: %s", response) LOG.debug("API response: %s", response)
raise SolidFireRetryableException(message=msg) raise SolidFireRetryableException(message=msg)
skipping to change at line 777 skipping to change at line 803
if not self.configuration.sf_emulate_512: if not self.configuration.sf_emulate_512:
conn_info['provider_geometry'] = ('%s %s' % (4096, 4096)) conn_info['provider_geometry'] = ('%s %s' % (4096, 4096))
conn_info['provider_id'] = ( conn_info['provider_id'] = (
self._create_provider_id_string(vol_id, sfaccount['accountID'])) self._create_provider_id_string(vol_id, sfaccount['accountID']))
return conn_info return conn_info
def _get_model_info(self, sfaccount, sf_volume_id, endpoint=None): def _get_model_info(self, sfaccount, sf_volume_id, endpoint=None):
volume = None volume = None
iteration_count = 0 volume_list = self._get_volumes_by_sfaccount(
while not volume and iteration_count < 600: sfaccount['accountID'], endpoint=endpoint)
volume_list = self._get_volumes_by_sfaccount(
sfaccount['accountID'], endpoint=endpoint) for v in volume_list:
for v in volume_list: if v['volumeID'] == sf_volume_id:
if v['volumeID'] == sf_volume_id: volume = v
volume = v break
break
iteration_count += 1
if not volume: if not volume:
LOG.error('Failed to retrieve volume SolidFire-' LOG.error('Failed to retrieve volume SolidFire-'
'ID: %s in get_by_account!', sf_volume_id) 'ID: %s in get_by_account!', sf_volume_id)
raise exception.VolumeNotFound(volume_id=sf_volume_id) raise exception.VolumeNotFound(volume_id=sf_volume_id)
model_update = self._build_connection_info(sfaccount, volume, model_update = self._build_connection_info(sfaccount, volume,
endpoint=endpoint) endpoint=endpoint)
return model_update return model_update
skipping to change at line 855 skipping to change at line 879
raise SolidFireAPIException(msg) raise SolidFireAPIException(msg)
sf_cloned_id = data['result']['volumeID'] sf_cloned_id = data['result']['volumeID']
# NOTE(jdg): all attributes are copied via clone, need to do an update # NOTE(jdg): all attributes are copied via clone, need to do an update
# to set any that were provided # to set any that were provided
params = self._get_default_volume_params(vref, is_clone=is_clone) params = self._get_default_volume_params(vref, is_clone=is_clone)
params['volumeID'] = sf_cloned_id params['volumeID'] = sf_cloned_id
data = self._issue_api_request('ModifyVolume', params) data = self._issue_api_request('ModifyVolume', params)
model_update = self._get_model_info(sf_account, sf_cloned_id) def _wait_volume_is_active():
if model_update is None: try:
mesg = _('Failed to get model update from clone') model_info = self._get_model_info(sf_account, sf_cloned_id)
raise SolidFireAPIException(mesg) if model_info:
raise loopingcall.LoopingCallDone(model_info)
except exception.VolumeNotFound:
LOG.debug('Waiting for cloned volume [%s] - [%s] to become '
'active', sf_cloned_id, vref.id)
pass
try:
timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(
_wait_volume_is_active)
model_update = timer.start(
interval=1,
timeout=self.configuration.sf_volume_clone_timeout).wait()
except loopingcall.LoopingCallTimeOut:
msg = (_('Failed to get model update from clone '
'%(cloned_id)s - %(vref_id)s') %
{'cloned_id': sf_cloned_id, 'vref_id': vref.id})
LOG.error(msg)
raise SolidFireAPIException(msg)
rep_settings = self._retrieve_replication_settings(vref) rep_settings = self._retrieve_replication_settings(vref)
if self.replication_enabled and rep_settings: if self.replication_enabled and rep_settings:
try: try:
vref['volumeID'] = sf_cloned_id vref['volumeID'] = sf_cloned_id
rep_updates = self._replicate_volume( rep_updates = self._replicate_volume(
vref, params, sf_account, rep_settings) vref, params, sf_account, rep_settings)
model_update.update(rep_updates) model_update.update(rep_updates)
except SolidFireDriverException: except SolidFireDriverException:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
skipping to change at line 889 skipping to change at line 931
def _update_attributes(self, sf_vol): def _update_attributes(self, sf_vol):
cloned_count = sf_vol['attributes'].get('cloned_count', 0) cloned_count = sf_vol['attributes'].get('cloned_count', 0)
cloned_count += 1 cloned_count += 1
attributes = sf_vol['attributes'] attributes = sf_vol['attributes']
attributes['cloned_count'] = cloned_count attributes['cloned_count'] = cloned_count
params = {'volumeID': int(sf_vol['volumeID'])} params = {'volumeID': int(sf_vol['volumeID'])}
params['attributes'] = attributes params['attributes'] = attributes
return self._issue_api_request('ModifyVolume', params) return self._issue_api_request('ModifyVolume', params)
def _list_volumes_by_name(self, sf_volume_name):
params = {'volumeName': sf_volume_name}
return self._issue_api_request(
'ListVolumes', params, version='8.0')['result']['volumes']
def _wait_volume_is_active(self, sf_volume_name):
def _wait():
volumes = self._list_volumes_by_name(sf_volume_name)
if volumes:
LOG.debug("Found Volume [%s] in SolidFire backend. "
"Current status is [%s].",
sf_volume_name, volumes[0]['status'])
if volumes[0]['status'] == 'active':
raise loopingcall.LoopingCallDone(volumes[0])
try:
timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(
_wait)
sf_volume = (timer.start(
interval=1,
timeout=self.configuration.sf_volume_create_timeout).wait())
return sf_volume
except loopingcall.LoopingCallTimeOut:
msg = ("Timeout while waiting volume [%s] "
"to be in active state." % sf_volume_name)
LOG.error(msg)
raise SolidFireAPIException(msg)
def _do_volume_create(self, sf_account, params, endpoint=None): def _do_volume_create(self, sf_account, params, endpoint=None):
params['accountID'] = sf_account['accountID']
sf_volid = self._issue_api_request( sf_volume_name = params['name']
'CreateVolume', params, endpoint=endpoint)['result']['volumeID'] volumes_found = self._list_volumes_by_name(sf_volume_name)
if volumes_found:
msg = ('Volume name [%s] already exists '
'in SolidFire backend.') % sf_volume_name
LOG.error(msg)
raise DuplicateSfVolumeNames(message=msg)
sf_volid = None
try:
params['accountID'] = sf_account['accountID']
response = self._issue_api_request(
'CreateVolume', params, endpoint=endpoint)
sf_volid = response['result']['volumeID']
except requests.exceptions.ReadTimeout:
LOG.debug("Read Timeout exception caught while creating "
"volume [%s].", sf_volume_name)
# Check if volume was created for the given name,
# in case the backend has processed the request but failed
# to deliver the response before api request timeout.
volume_created = self._wait_volume_is_active(sf_volume_name)
sf_volid = volume_created['volumeID']
return self._get_model_info(sf_account, sf_volid, endpoint=endpoint) return self._get_model_info(sf_account, sf_volid, endpoint=endpoint)
def _do_snapshot_create(self, params): def _do_snapshot_create(self, params):
model_update = {} model_update = {}
snapshot_id = self._issue_api_request( snapshot_id = self._issue_api_request(
'CreateSnapshot', params, version='6.0')['result']['snapshotID'] 'CreateSnapshot', params, version='6.0')['result']['snapshotID']
snaps = self._get_sf_snapshots() snaps = self._get_sf_snapshots()
snap = ( snap = (
next((s for s in snaps if int(s["snapshotID"]) == next((s for s in snaps if int(s["snapshotID"]) ==
int(snapshot_id)), None)) int(snapshot_id)), None))
 End of changes. 12 change blocks. 
21 lines changed or deleted 115 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)