def create_share(self, share, share_server=None): """Create a share.""" share_name = share['name'] share_proto = share['share_proto'] pool_name = share_utils.extract_host(share['host'], level='pool') if not pool_name: msg = _("Pool is not available in the share host field.") raise exception.InvalidHost(reason=msg) result = self.helper._find_all_pool_info() poolinfo = self.helper._find_pool_info(pool_name, result) if not poolinfo: msg = (_("Can not find pool info by pool name: %s") % pool_name) raise exception.InvalidHost(reason=msg) fs_id = None # We sleep here to ensure the newly created filesystem can be read. wait_interval = self._get_wait_interval() timeout = self._get_timeout() try: fs_id = self.allocate_container(share, poolinfo) fs = self.helper._get_fs_info_by_id(fs_id) end_time = time.time() + timeout while not (self.check_fs_status(fs['HEALTHSTATUS'], fs['RUNNINGSTATUS']) or time.time() > end_time): time.sleep(wait_interval) fs = self.helper._get_fs_info_by_id(fs_id) if not self.check_fs_status(fs['HEALTHSTATUS'], fs['RUNNINGSTATUS']): raise exception.InvalidShare( reason=(_('Invalid status of filesystem: %(health)s ' '%(running)s.') % {'health': fs['HEALTHSTATUS'], 'running': fs['RUNNINGSTATUS']})) except Exception as err: if fs_id is not None: self.helper._delete_fs(fs_id) message = (_('Failed to create share %(name)s.' 'Reason: %(err)s.') % {'name': share_name, 'err': err}) raise exception.InvalidShare(reason=message) try: self.helper._create_share(share_name, fs_id, share_proto) except Exception as err: if fs_id is not None: self.helper._delete_fs(fs_id) raise exception.InvalidShare( reason=(_('Failed to create share %(name)s. Reason: %(err)s.') % {'name': share_name, 'err': err})) location = self._get_location_path(share_name, share_proto) return location
def delete(self, context, share, force=False): """Delete share.""" share = self.db.share_get(context, share['id']) if context.is_admin and context.project_id != share['project_id']: project_id = share['project_id'] else: project_id = context.project_id share_id = share['id'] statuses = (constants.STATUS_AVAILABLE, constants.STATUS_ERROR, constants.STATUS_INACTIVE) if not (force or share['status'] in statuses): msg = _("Share status must be one of %(statuses)s") % { "statuses": statuses } raise exception.InvalidShare(reason=msg) snapshots = self.db.share_snapshot_get_all_for_share(context, share_id) if len(snapshots): msg = _("Share still has %d dependent snapshots") % len(snapshots) raise exception.InvalidShare(reason=msg) cgsnapshot_members_count = self.db.count_cgsnapshot_members_in_share( context, share_id) if cgsnapshot_members_count: msg = (_("Share still has %d dependent cgsnapshot members") % cgsnapshot_members_count) raise exception.InvalidShare(reason=msg) # Make sure share is not part of a migration if share['task_state'] not in ( None, constants.STATUS_TASK_STATE_MIGRATION_ERROR, constants.STATUS_TASK_STATE_MIGRATION_SUCCESS): msg = _("Share %s is busy as part of an active " "task.") % share['id'] LOG.error(msg) raise exception.InvalidShare(reason=msg) try: reservations = QUOTAS.reserve(context, project_id=project_id, shares=-1, gigabytes=-share['size']) except Exception as e: reservations = None LOG.exception(_LE("Failed to update quota for deleting share: %s"), six.text_type(e)) ownername = context.user_id #lease.delete_success(share['id'], ownername) for share_instance in share.instances: if share_instance['host']: self.delete_instance(context, share_instance, force=force) else: self.db.share_instance_delete(context, share_instance['id']) if reservations: QUOTAS.commit(context, reservations, project_id=project_id)
def shrink_share(self, share, new_size, share_server): """Shrinks size of existing share.""" share_proto = share['share_proto'] share_name = share['name'] # The unit is in sectors. size = int(new_size) * units.Mi * 2 share_url_type = self.helper._get_share_url_type(share_proto) share = self.helper._get_share_by_name(share_name, share_url_type) if not share: err_msg = (_("Can not get share ID by share %s.") % share_name) LOG.error(err_msg) raise exception.InvalidShare(reason=err_msg) fsid = share['FSID'] fs_info = self.helper._get_fs_info_by_id(fsid) if not fs_info: err_msg = (_("Can not get filesystem info by filesystem ID: %s.") % fsid) LOG.error(err_msg) raise exception.InvalidShare(reason=err_msg) current_size = int(fs_info['CAPACITY']) / units.Mi / 2 if current_size < new_size: err_msg = (_("New size for shrink must be less than current " "size on array. (current: %(size)s, " "new: %(new_size)s).") % { 'size': current_size, 'new_size': new_size }) LOG.error(err_msg) raise exception.InvalidShare(reason=err_msg) self.helper._change_share_size(fsid, size)
def xml_response_check(self, xmlout, command, countpath=None): """Sanity check for GlusterFS XML response.""" commandstr = ' '.join(command) ret = {} for e in 'opRet', 'opErrno': ret[e] = int(volxml_get(xmlout, e)) if ret == {'opRet': -1, 'opErrno': 0}: raise exception.GlusterfsException(_( 'GlusterFS command %(command)s on volume %(volume)s failed' ) % {'volume': self.volume, 'command': command}) if list(six.itervalues(ret)) != [0, 0]: errdct = {'volume': self.volume, 'command': commandstr, 'opErrstr': volxml_get(xmlout, 'opErrstr', default=None)} errdct.update(ret) raise exception.InvalidShare(_( 'GlusterFS command %(command)s on volume %(volume)s got ' 'unexpected response: ' 'opRet=%(opRet)s, opErrno=%(opErrno)s, opErrstr=%(opErrstr)s' ) % errdct) if not countpath: return count = volxml_get(xmlout, countpath) if count != '1': raise exception.InvalidShare( _('GlusterFS command %(command)s on volume %(volume)s got ' 'ambiguous response: ' '%(count)s records') % { 'volume': self.volume, 'command': commandstr, 'count': count})
def allow_access(self, ctx, share, access_type, access_to): """Allow access to share.""" if not share['host']: msg = _("Share host is None") raise exception.InvalidShare(reason=msg) if share['status'] not in ["available"]: msg = _("Share status must be available") raise exception.InvalidShare(reason=msg) policy.check_policy(ctx, 'share', 'allow_access') values = { 'share_id': share['id'], 'access_type': access_type, 'access_to': access_to } access = [ a for a in self.db.share_access_get_all_by_type_and_access( ctx, share['id'], access_type, access_to) if a['state'] != 'error' ] if access: raise exception.ShareAccessExists(access_type=access_type, access=access_to) access = self.db.share_access_create(ctx, values) self.share_rpcapi.allow_access(ctx, share, access) return access
def unmanage_share(self, context, share_id): context = context.elevated() share_ref = self.db.share_get(context, share_id) share_server = self._get_share_server(context, share_ref) project_id = share_ref['project_id'] def share_manage_set_error_status(msg, exception): status = {'status': constants.STATUS_UNMANAGE_ERROR} self.db.share_update(context, share_id, status) LOG.error(msg, six.text_type(exception)) try: if self.driver.driver_handles_share_servers: msg = _("Unmanage share is not supported for " "driver_handles_share_servers=True mode.") raise exception.InvalidShare(reason=msg) if share_server: msg = _("Unmanage share is not supported for " "shares with share servers.") raise exception.InvalidShare(reason=msg) self.driver.unmanage(share_ref) except exception.InvalidShare as e: share_manage_set_error_status( _LE("Share can not be unmanaged: %s."), e) return try: reservations = QUOTAS.reserve(context, project_id=project_id, shares=-1, gigabytes=-share_ref['size']) QUOTAS.commit(context, reservations, project_id=project_id) except Exception as e: # Note(imalinovskiy): # Quota reservation errors here are not fatal, because # unmanage is administrator API and he/she could update user # quota usages later if it's required. LOG.warning(_LE("Failed to update quota usages: %s."), six.text_type(e)) if self.configuration.safe_get('unmanage_remove_access_rules'): try: self._remove_share_access_rules(context, share_ref, share_server) except Exception as e: share_manage_set_error_status( _LE("Can not remove access rules of share: %s."), e) return self.db.share_update(context, share_id, {'status': constants.STATUS_UNMANAGED, 'deleted': True})
def delete(self, context, share, force=False): """Delete share.""" share = self.db.share_get(context, share['id']) if context.is_admin and context.project_id != share['project_id']: project_id = share['project_id'] else: project_id = context.project_id share_id = share['id'] statuses = (constants.STATUS_AVAILABLE, constants.STATUS_ERROR, constants.STATUS_INACTIVE) if not (force or share['status'] in statuses): msg = _("Share status must be one of %(statuses)s") % { "statuses": statuses } raise exception.InvalidShare(reason=msg) snapshots = self.db.share_snapshot_get_all_for_share(context, share_id) if len(snapshots): msg = _("Share still has %d dependent snapshots") % len(snapshots) raise exception.InvalidShare(reason=msg) cgsnapshot_members_count = self.db.count_cgsnapshot_members_in_share( context, share_id) if cgsnapshot_members_count: msg = (_("Share still has %d dependent cgsnapshot members") % cgsnapshot_members_count) raise exception.InvalidShare(reason=msg) self._check_is_share_busy(share) try: reservations = QUOTAS.reserve(context, project_id=project_id, shares=-1, gigabytes=-share['size']) except Exception as e: reservations = None LOG.exception(_LE("Failed to update quota for deleting share: %s"), six.text_type(e)) for share_instance in share.instances: if share_instance['host']: self.delete_instance(context, share_instance, force=force) else: self.db.share_instance_delete(context, share_instance['id']) if reservations: QUOTAS.commit(context, reservations, project_id=project_id)
def delete(self, context, share, force=False): """Delete share.""" if context.is_admin and context.project_id != share['project_id']: project_id = share['project_id'] else: project_id = context.project_id share_id = share['id'] if not share['host']: try: reservations = QUOTAS.reserve(context, project_id=project_id, shares=-1, gigabytes=-share['size']) except Exception: reservations = None LOG.exception(_LE("Failed to update quota for deleting share")) self.db.share_delete(context.elevated(), share_id) if reservations: QUOTAS.commit(context, reservations, project_id=project_id) return if not (force or share['status'] in ["available", "error"]): msg = _("Share status must be available or error") raise exception.InvalidShare(reason=msg) snapshots = self.db.share_snapshot_get_all_for_share(context, share_id) if len(snapshots): msg = _("Share still has %d dependent snapshots") % len(snapshots) raise exception.InvalidShare(reason=msg) now = timeutils.utcnow() share = self.db.share_update(context, share_id, { 'status': 'deleting', 'terminated_at': now }) self.share_rpcapi.delete_share(context, share) # NOTE(u_glide): 'updated_at' timestamp is used to track last usage of # share server. This is required for automatic share servers cleanup # because we should track somehow period of time when share server # doesn't have shares (unused). We do this update only on share # deletion because share server with shares cannot be deleted, so no # need to do this update on share creation or any other share operation if share['share_server_id']: self.db.share_server_update(context, share['share_server_id'], {'updated_at': timeutils.utcnow()})
def create_share_from_snapshot(self, context, share, snapshot, share_server=None): """Create a share from a snapshot - clone a snapshot.""" share_name = share['id'] share_proto = share['share_proto'].upper() # Validate the share protocol if share_proto not in ('NFS', 'CIFS'): raise exception.InvalidShare( reason=(_('Invalid NAS protocol supplied: %s.') % share_proto)) # Get the pool name from share host field pool_name = share_utils.extract_host(share['host'], level='pool') if not pool_name: message = (_("Pool is not available in the share host %s.") % share['host']) raise exception.InvalidHost(reason=message) self._share_server_validation(share_server) self._allocate_container_from_snapshot( share, snapshot, share_server, pool_name) if share_proto == 'NFS': self._create_nfs_share(share_name, share_server) location = ('%(nfs_if)s:/%(share_name)s' % {'nfs_if': share_server['backend_details']['nfs_if'], 'share_name': share_name}) elif share_proto == 'CIFS': location = self._create_cifs_share(share_name, share_server) return location
def _get_gluster_vol_option(self, option): try: args, kw = self.gluster_address.make_gluster_args( '--xml', 'volume', 'info', self.gluster_address.volume ) out, err = self._execute(*args, **kw) except exception.ProcessExecutionError as exc: LOG.error(_LE("Error retrieving volume info: %s"), exc.stderr) raise exception.GlusterfsException(exc) if not out: raise exception.GlusterfsException( 'Empty answer from gluster command' ) vix = etree.fromstring(out) if int(vix.find('./volInfo/volumes/count').text) != 1: raise exception.InvalidShare('Volume name ambiguity') for e in vix.findall(".//option"): o, v = (e.find(a).text for a in ('name', 'value')) if o == option: return v
def login(self): """Login huawei array.""" login_info = self._get_login_info() urlstr = login_info['RestURL'] url_list = urlstr.split(";") deviceid = None for item_url in url_list: url = item_url.strip('').strip('\n') + "xx/sessions" data = jsonutils.dumps({ "username": login_info['UserName'], "password": login_info['UserPassword'], "scope": "0" }) self.init_http_head() result = self.do_call(url, data, calltimeout=constants.LOGIN_SOCKET_TIMEOUT) if ((result['error']['code'] != 0) or ("data" not in result) or (result['data']['deviceid'] is None)): LOG.error(_LE("Login to %s failed, try another."), item_url) continue LOG.debug('Login success: %(url)s\n', {'url': item_url}) deviceid = result['data']['deviceid'] self.url = item_url + deviceid self.headers['iBaseToken'] = result['data']['iBaseToken'] break if deviceid is None: err_msg = _("All url login fail.") LOG.error(err_msg) raise exception.InvalidShare(reason=err_msg) return deviceid
def create_share(self, context, share, share_server=None): """Create a share and export it based on protocol used.""" size = share["size"] * units.Gi share_name = self._make_share_name(share) if share["share_proto"] == "NFS": flashblade_fs = purity_fb.FileSystem( name=share_name, provisioned=size, hard_limit_enabled=True, fast_remove_directory_enabled=True, snapshot_directory_enabled=True, nfs=purity_fb.NfsRule(v3_enabled=True, rules="", v4_1_enabled=True), ) self._sys.file_systems.create_file_systems(flashblade_fs) location = self._get_full_nfs_export_path(share_name) else: message = _("Unsupported share protocol: %(proto)s.") % { "proto": share["share_proto"] } LOG.exception(message) raise exception.InvalidShare(reason=message) LOG.info("FlashBlade created share %(name)s", {"name": share_name}) return location
def allocate_container(self, share, poolinfo): """Creates filesystem associated to share by name.""" opts = huawei_utils.get_share_extra_specs_params( share['share_type_id']) smartx_opts = constants.OPTS_CAPABILITIES if opts is not None: smart = smartx.SmartX() smartx_opts = smart.get_smartx_extra_specs_opts(opts) fileParam = self._init_filesys_para(share, poolinfo, smartx_opts) fsid = self.helper._create_filesystem(fileParam) try: smartpartition = smartx.SmartPartition(self.helper) smartpartition.add(opts, fsid) smartcache = smartx.SmartCache(self.helper) smartcache.add(opts, fsid) except Exception as err: if fsid is not None: self.helper._delete_fs(fsid) message = (_('Failed to add smartx. Reason: %(err)s.') % {'err': err}) raise exception.InvalidShare(reason=message) return fsid
def _get_helper(self, share): if share['share_proto'].startswith('NFS'): return self._helpers['NFS'] elif share['share_proto'].startswith('CIFS'): return self._helpers['CIFS'] else: raise exception.InvalidShare(reason='Wrong share type')
def _get_helper(self, share): if share['share_proto'].lower().startswith('nfs'): return self._helpers['NFS'] elif share['share_proto'].lower().startswith('cifs'): return self._helpers['CIFS'] else: raise exception.InvalidShare(reason='Wrong share protocol')
def _get_helper(self, share): helper = self._helpers.get(share['share_proto']) if helper: return helper else: raise exception.InvalidShare( reason="Wrong, unsupported or disabled protocol")
def create_share(self, context, share, share_server=None): LOG.debug("Creating share in HSP: %(shr)s", {'shr': share['id']}) if share['share_proto'].lower() != 'nfs': msg = _("Only NFS protocol is currently supported.") raise exception.InvalidShare(reason=msg) self.hsp.add_file_system(share['id'], share['size'] * units.Gi) filesystem_id = self.hsp.get_file_system(share['id'])['id'] try: self.hsp.add_share(share['id'], filesystem_id) except exception.HSPBackendException: with excutils.save_and_reraise_exception(): self.hsp.delete_file_system(filesystem_id) msg = _LE("Could not create share %s on HSP.") LOG.exception(msg, share['id']) uri = self.hsp_host + ':/' + share['id'] LOG.debug("Share created successfully on path: %(uri)s.", {'uri': uri}) return [{ "path": uri, "metadata": {}, "is_admin_only": False, }]
def _get_login_info(self): """Get login IP, username and password from config file.""" logininfo = {} filename = self.configuration.manila_huawei_conf_file tree = ET.parse(filename) root = tree.getroot() RestURL = root.findtext('Storage/RestURL') logininfo['RestURL'] = RestURL.strip() # Prefix !$$$ means encoded already. prefix_name = '!$$$' need_encode = False for key in ['UserName', 'UserPassword']: node = root.find('Storage/%s' % key) if node.text.find(prefix_name) > -1: logininfo[key] = base64.b64decode(six.b(node.text[4:])) else: logininfo[key] = node.text node.text = prefix_name + six.text_type( base64.b64encode(six.b(node.text))) need_encode = True if need_encode: self._change_file_mode(filename) try: tree.write(filename, 'UTF-8') except Exception as err: err_msg = (_('File write error %s.') % err) LOG.error(err_msg) raise exception.InvalidShare(reason=err_msg) return logininfo
def _verify_share_protocol(self, share): if share['share_proto'] != 'NFS': reason = (_('Unsupported share protocol: %(proto)s.') % { 'proto': share['share_proto'] }) LOG.error(reason) raise exception.InvalidShare(reason=reason)
def get_smartprovisioning_opts(self, opts): thin_provision = opts.get('thin_provisioning') if thin_provision is None: root = self.helper._read_xml() fstype = root.findtext('Filesystem/AllocType') if fstype: fstype = fstype.strip().strip('\n') if fstype == 'Thin': opts['LUNType'] = constants.ALLOC_TYPE_THIN_FLAG elif fstype == 'Thick': opts['LUNType'] = constants.ALLOC_TYPE_THICK_FLAG else: err_msg = (_( 'Huawei config file is wrong. AllocType type must be ' 'set to "Thin" or "Thick". AllocType:%(fetchtype)s') % { 'fetchtype': fstype }) raise exception.InvalidShare(reason=err_msg) else: opts['LUNType'] = constants.ALLOC_TYPE_THICK_FLAG else: if strutils.bool_from_string(thin_provision): opts['LUNType'] = constants.ALLOC_TYPE_THIN_FLAG else: opts['LUNType'] = constants.ALLOC_TYPE_THICK_FLAG return opts
def create_share_from_snapshot(self, emc_share_driver, context, share, snapshot, share_server=None): """Is called to create share from snapshot.""" share_name = share['name'] vdm_ref = self.share_server_validation(share_server) self.allocate_container_from_snapshot(share, snapshot, vdm_ref) if share['share_proto'].startswith('NFS'): self._create_nfs_share(share_name, vdm_ref['name'], share_server) location = ('%(nfs_if)s:/%(share_name)s' % { 'nfs_if': share_server['backend_details']['nfs_if'], 'share_name': share_name }) elif share['share_proto'].startswith('CIFS'): location = self._create_cifs_share(share_name, vdm_ref) else: raise exception.InvalidShare( reason=(_('Invalid NAS protocol supplied: %s.') % share['share_proto'])) return location
def create_share(self, ctx, share, share_server=None): """Create new share on HDS Scale-out Platform.""" sharesize = int(six.text_type(share['size'])) httpclient = httplib2.Http(disable_ssl_certificate_validation=True, timeout=None) if share['share_proto'] != 'NFS': raise exception.InvalidShare( reason=(_('Invalid NAS protocol supplied: %s.') % share['share_proto'])) payload = { 'quota': sharesize * units.Gi, 'enabled': True, 'description': '', 'record-access-time': True, 'tags': '', 'space-hwm': 90, 'space-lwm': 70, 'name': share['id'], } self._add_file_system_sopapi(httpclient, payload) payload = { 'description': '', 'type': 'NFS', 'enabled': True, 'tags': '', 'name': share['id'], 'file-system-id': self._get_file_system_id_by_name( httpclient, share['id']), } return self.sop_target + ':/' + self._add_share_sopapi( httpclient, payload)
def _get_helper(self, share): """Choose a protocol specific helper class.""" if share['share_proto'] == 'NFS': return self._helpers['NFS'] else: raise exception.InvalidShare( reason=(_('Unsupported share type, %s.') % share['share_proto']))
def _get_location_path(self, path, protocol): location = None if protocol == 'NFS': location = {'path': '%s:/volumes/%s' % (self.nms_host, path)} else: raise exception.InvalidShare( reason=(_('Only NFS protocol is currently supported.'))) return location
def test_create_share_error_unsupported_share_type(self): self.mock_object( self._driver, '_get_helper', mock.Mock(side_effect=exception.InvalidShare( reason="Unsupported Share type"))) self.assertRaises(exception.InvalidShare, self._driver.create_share, self._context, self.share) self._driver._get_helper.assert_called_once_with(self.share)
def _assert_rest_result(self, result, err_str): if result['error']['code'] != 0: err_msg = (_('%(err)s\nresult: %(res)s.') % { 'err': err_str, 'res': result }) LOG.error(err_msg) raise exception.InvalidShare(reason=err_msg)
def _get_helper(self, share): if share['share_proto'] == 'NFS': return self._helpers[self.configuration.gpfs_nfs_server_type] else: msg = (_('Share protocol %s not supported by GPFS driver.') % share['share_proto']) LOG.error(msg) raise exception.InvalidShare(reason=msg)
def manage_share(self, context, share_id, driver_options): context = context.elevated() share_ref = self.db.share_get(context, share_id) project_id = share_ref['project_id'] try: if self.driver.driver_handles_share_servers: msg = _("Manage share is not supported for " "driver_handles_share_servers=True mode.") raise exception.InvalidShare(reason=msg) share_update = ( self.driver.manage_existing(share_ref, driver_options) or {}) if not share_update.get('size'): msg = _("Driver cannot calculate share size.") raise exception.InvalidShare(reason=msg) self._update_quota_usages(context, project_id, { "shares": 1, "gigabytes": share_update['size'], }) share_update.update({ 'status': 'available', 'launched_at': timeutils.utcnow(), }) # NOTE(vponomaryov): we should keep only those export locations # that driver has calculated to avoid incompatibilities with one # provided by user. if 'export_locations' in share_update: self.db.share_export_locations_update( context, share_id, share_update.pop('export_locations'), delete=True) self.db.share_update(context, share_id, share_update) except Exception: # NOTE(vponomaryov): set size as 1 because design expects size # to be set, it also will allow us to handle delete/unmanage # operations properly with this errored share according to quotas. self.db.share_update( context, share_id, {'status': constants.STATUS_MANAGE_ERROR, 'size': 1}) raise
def volxml_get(xmlout, path, *default): """Extract a value by a path from XML.""" value = xmlout.find(path) if value is None: if default: return default[0] raise exception.InvalidShare( _('Xpath %s not found in volume query response XML') % path) return value.text
def extend(self, context, share, new_size): policy.check_policy(context, 'share', 'extend') if share['status'] != constants.STATUS_AVAILABLE: msg_params = { 'valid_status': constants.STATUS_AVAILABLE, 'share_id': share['id'], 'status': share['status'], } msg = _("Share %(share_id)s status must be '%(valid_status)s' " "to extend, but current status is: " "%(status)s.") % msg_params raise exception.InvalidShare(reason=msg) self._check_is_share_busy(share) size_increase = int(new_size) - share['size'] if size_increase <= 0: msg = (_("New size for extend must be greater " "than current size. (current: %(size)s, " "extended: %(new_size)s).") % { 'new_size': new_size, 'size': share['size'] }) raise exception.InvalidInput(reason=msg) try: reservations = QUOTAS.reserve(context, project_id=share['project_id'], gigabytes=size_increase) except exception.OverQuota as exc: usages = exc.kwargs['usages'] quotas = exc.kwargs['quotas'] def _consumed(name): return usages[name]['reserved'] + usages[name]['in_use'] msg = _LE("Quota exceeded for %(s_pid)s, tried to extend share " "by %(s_size)sG, (%(d_consumed)dG of %(d_quota)dG " "already consumed).") LOG.error( msg, { 's_pid': context.project_id, 's_size': size_increase, 'd_consumed': _consumed('gigabytes'), 'd_quota': quotas['gigabytes'] }) raise exception.ShareSizeExceedsAvailableQuota( requested=size_increase, consumed=_consumed('gigabytes'), quota=quotas['gigabytes']) self.update(context, share, {'status': constants.STATUS_EXTENDING}) self.share_rpcapi.extend_share(context, share, new_size, reservations) LOG.info(_LI("Extend share request issued successfully."), resource=share)