def _list_volumes(self, req, body): """ Returns Cinder volume lists for specific query params :param req: python-cinderclient request :param body: python-cinderclient request's body {"list-volumes": {"node_id": "<node_id>"}} :return: {"count": <count>, "volumes": [ {<volume data 1st volume>}, {<volume data 2nd volume>}, ... ]} """ cinder_context = req.environ['cinder.context'] authorize_list_volumes(cinder_context) admin_context = cinder.context.get_admin_context() kwargs = SafeDict(body).get('list-volumes', {}) tenant_id = 'admin' lunr_client = lunrclient.client.LunrClient(tenant_id) data_name = "volumes" if 'node_id' in kwargs: lunr_node = lunr_except_handler(lambda: lunr_client.nodes.get(node_id=kwargs['node_id'])) hostname = lunr_node['cinder_host'] cinder_volumes = cinder_list_handler(volume_get_all_by_host(admin_context, host=hostname), data_name) return cinder_volumes if 'restore_of' in kwargs: lunr_volumes = lunr_except_handler(lambda: lunr_client.volumes.list(restore_of=kwargs['restore_of'])) cinder_volumes_list = [] if len(lunr_volumes) > 0: for volume in lunr_volumes: if 'id' in volume: cinder_volumes_list.append(volume_get(admin_context, volume_id=volume['id'])) if isinstance(cinder_volumes_list, list): cinder_volumes = {"count": len(cinder_volumes_list), data_name: cinder_volumes_list} else: cinder_volumes = {"count": 0, "volumes": cinder_volumes_list} return cinder_volumes elif 'id' in kwargs: cinder_volumes = cinder_list_handler(volume_get(admin_context, volume_id=kwargs['id']), data_name) return cinder_volumes elif 'account_id' in kwargs: filters = {'project_id': kwargs['account_id']} cinder_volumes = cinder_list_handler(volume_get_all(admin_context, marker=None, limit=None, sort_keys=['project_id'], sort_dirs=['asc'], filters=filters), data_name) return cinder_volumes elif 'host' in kwargs: filters = {'host': kwargs['host']} cinder_volumes = cinder_list_handler(volume_get_all(admin_context, marker=None, limit=None, sort_keys=['project_id'], sort_dirs=['asc'], filters=filters), data_name) return cinder_volumes raise exc.HTTPBadRequest( explanation=_("Must specify node_id, restore_of, id, account_id, or host"))
def _get_volume(self, req, body): """ Returns Lunr, Cinder, and storage node GET data for a volume :param req: python-cinderclient request :param body: python-cinderclinet request's body {"get-volume": {"id": "<volume_id>"}} :return: {"volume": {"storage_volumes": {<storage_volumes vol 1>}, "storage_backups": [{<storage_backups backup 1>}, {backup 2}, ...], "storage_exports": [{<storage_exports export 1>}, {export 2 ?}, ...], "lunr_nodes": {<lunr_nodes data>}, "lunr_backups": [{<lunr_backups data backup 1>}, {backup 2}, ...], "lunr_exports": [{<lunr_exports data export 1>}, {export 2 ?}, ...], "lunr_volumes": {<lunr_volumes data>}, "cinder_volumes": {<cinder volume data>} } """ cinder_context = req.environ['cinder.context'] authorize_get_volume(cinder_context) volume_id = str(SafeDict(body).get('get-volume', {}).get('id')) volume = {} lunr_backups = [] tenant_id = 'admin' # Get Lunr specific data for volume lunr_client = lunrclient.client.LunrClient(tenant_id) lunr_volumes = lunr_except_handler(lambda: lunr_client.volumes.get(volume_id)) lunr_exports = lunr_except_handler(lambda: lunr_client.exports.get(volume_id)) # Get Lunr node id information for direct storage node query lunr_nodes = lunr_except_handler(lambda: lunr_client.nodes.get(lunr_volumes['node_id'])) volume.update(dict(lunr_volumes=lunr_volumes)) if lunr_exports['code'] == 200: volume.update(dict(lunr_exports=[lunr_exports])) volume.update(dict(lunr_nodes=lunr_nodes)) # Get volume data specific to the storage node resource (direct from storage node) url = 'http://' + lunr_nodes['hostname'] + ':8080/' + CONF.lunr_api_version + '/admin' storage_client = lunrclient.client.StorageClient(url) storage_volumes = lunr_except_handler(lambda: storage_client.volumes.get(volume_id)) storage_exports = lunr_except_handler(lambda: storage_client.exports.get(volume_id)) storage_backups = lunr_except_handler(lambda: storage_client.backups.list(volume_id)) # Add storage node response data to volume dictionary volume.update(dict(storage_volumes=storage_volumes)) if storage_exports['code'] == 200: volume.update(dict(storage_exports=[storage_exports])) volume.update(dict(storage_backups=[storage_backups])) # Now that storage_backup list has been identified # Lunr can be queried specifically for each backup # *** Should actually use lunr backups and query by kwargs # that contain account_id and volume id if len(storage_backups) > 1: for k, v in storage_backups.iteritems(): if k != 'code': lunr_backups.append(lunr_except_handler(lambda: lunr_client.backups.get(k))) volume.update(dict(lunr_backups=lunr_backups)) else: # storage_backup only had a 404 error code # No backups to iterate over. volume.update(dict(lunr_backups=[])) # Now add cinder volume data to the volume dictionary volume.update({"cinder_volumes": volume_get(cinder_context, volume_id)}) return dict(volume=volume)
def test_set_volume(self): res = sqla_api.volume_get_all(self.context) self.assertListEqual([], res) vol = cinderlib.Volume(self.backend, size=1, name='disk') expected = {'availability_zone': vol.availability_zone, 'size': vol.size, 'name': vol.name} self.persistence.set_volume(vol) db_vol = sqla_api.volume_get(self.context, vol.id) actual = {'availability_zone': db_vol.availability_zone, 'size': db_vol.size, 'name': db_vol.display_name} self.assertDictEqual(expected, actual)
def create_snapshot(self, snapshot): """Create a disco snapshot.""" volume = api.volume_get(self.ctxt, snapshot['volume_id']) description = snapshot['display_description'] vol_id = volume['provider_location'] LOG.debug( "Create snapshot of volume : %(id)s, " "description : %(desc)s.", { 'id': vol_id, 'desc': description }) # Trigger an asynchronous local snapshot reply = self.client.service.snapshotCreate(vol_id, -1, -1, description) status = reply['status'] result = reply['result'] LOG.debug("Create snapshot : [status] %(stat)s - [result] %(res)s.", { 'stat': six.text_type(status), 'res': result }) if status != 0: msg = (_("Error while creating snapshot " "[status] %(stat)s - [result] %(res)s.") % { 'stat': six.text_type(status), 'res': result }) LOG.error(msg) raise exception.VolumeBackendAPIException(data=msg) # Monitor the status until it becomes either success or fail params = {'snapshot_id': int(result)} start_time = int(time.time()) timer = loopingcall.FixedIntervalLoopingCall( self._retry_get_detail, start_time, self.configuration.snapshot_check_timeout, 'snapshot_detail', params) reply = timer.start(interval=self.configuration.retry_interval).wait() snapshot['provider_location'] = result LOG.debug("snapshot taken successfully on volume : %(volume)s.", {'volume': volume['name']}) return {'provider_location': result}
def create_snapshot(self, snapshot): """Create a disco snapshot.""" volume = api.volume_get(self.ctxt, snapshot['volume_id']) description = snapshot['display_description'] vol_id = volume['provider_location'] LOG.debug("Create snapshot of volume : %(id)s, " "description : %(desc)s.", {'id': vol_id, 'desc': description}) # Trigger an asynchronous local snapshot reply = self.client.service.snapshotCreate(vol_id, -1, -1, description) status = reply['status'] result = reply['result'] LOG.debug("Create snapshot : [status] %(stat)s - [result] %(res)s.", {'stat': six.text_type(status), 'res': result}) if status != 0: msg = (_("Error while creating snapshot " "[status] %(stat)s - [result] %(res)s.") % {'stat': six.text_type(status), 'res': result}) LOG.error(msg) raise exception.VolumeBackendAPIException(data=msg) # Monitor the status until it becomes either success or fail params = {'snapshot_id': int(result)} start_time = int(time.time()) timer = loopingcall.FixedIntervalLoopingCall( self._retry_get_detail, start_time, self.configuration.snapshot_check_timeout, 'snapshot_detail', params) reply = timer.start(interval=self.configuration.retry_interval).wait() snapshot['provider_location'] = result LOG.debug("snapshot taken successfully on volume : %(volume)s.", {'volume': volume['name']}) return {'provider_location': result}
def _ensure_snapshot_resource_area(self, volume_id): """Make sure concerto snapshot resource area exists on volume. :param volume_id: Cinder volume ID corresponding to the backend LUN Exceptions: VolumeBackendAPIException: if cinder volume does not exist on backnd, or SRA could not be created. """ ctxt = context.get_admin_context() volume = api.volume_get(ctxt, volume_id) pool = None if not volume: msg = (_("Failed to ensure snapshot resource area, could not " "locate volume for id %s") % volume_id) raise exception.VolumeBackendAPIException(data=msg) if not self.vmem_mg.snapshot.lun_has_a_snapshot_resource( lun=volume_id): # Per Concerto documentation, the SRA size should be computed # as follows # Size-of-original-LUN Reserve for SRA # < 500MB 100% # 500MB to 2G 50% # >= 2G 20% # Note: cinder volume.size is in GB, vmemclient wants MB. lun_size_mb = volume['size'] * units.Ki if lun_size_mb < 500: snap_size_mb = lun_size_mb elif lun_size_mb < 2000: snap_size_mb = 0.5 * lun_size_mb else: snap_size_mb = 0.2 * lun_size_mb snap_size_mb = int(math.ceil(snap_size_mb)) typeid = volume['volume_type_id'] if typeid: pool = self._get_violin_extra_spec(volume, "storage_pool") LOG.debug("Creating SRA of %(ssmb)sMB for lun of %(lsmb)sMB " "on %(vol_id)s.", {'ssmb': snap_size_mb, 'lsmb': lun_size_mb, 'vol_id': volume_id}) res = self.vmem_mg.snapshot.create_snapshot_resource( lun=volume_id, size=snap_size_mb, enable_notification=False, policy=CONCERTO_DEFAULT_SRA_POLICY, enable_expansion=CONCERTO_DEFAULT_SRA_ENABLE_EXPANSION, expansion_threshold=CONCERTO_DEFAULT_SRA_EXPANSION_THRESHOLD, expansion_increment=CONCERTO_DEFAULT_SRA_EXPANSION_INCREMENT, expansion_max_size=CONCERTO_DEFAULT_SRA_EXPANSION_MAX_SIZE, enable_shrink=CONCERTO_DEFAULT_SRA_ENABLE_SHRINK, storage_pool=pool) if (not res['success']): msg = (_("Failed to create snapshot resource area on " "volume %(vol)s: %(res)s.") % {'vol': volume_id, 'res': res['msg']}) raise exception.VolumeBackendAPIException(data=msg)
def _ensure_snapshot_resource_area(self, volume_id): """Make sure concerto snapshot resource area exists on volume. :param volume_id: Cinder volume ID corresponding to the backend LUN :raises: VolumeBackendAPIException: if cinder volume does not exist on backnd, or SRA could not be created. """ ctxt = context.get_admin_context() volume = api.volume_get(ctxt, volume_id) spec_dict = {} if not volume: msg = (_("Failed to ensure snapshot resource area, could not " "locate volume for id %s") % volume_id) raise exception.VolumeBackendAPIException(data=msg) if not self.vmem_mg.snapshot.lun_has_a_snapshot_resource( lun=volume_id): # Per Concerto documentation, the SRA size should be computed # as follows # Size-of-original-LUN Reserve for SRA # < 500MB 100% # 500MB to 2G 50% # >= 2G 20% # Note: cinder volume.size is in GB, vmemclient wants MB. lun_size_mb = volume['size'] * units.Ki if lun_size_mb < 500: snap_size_mb = lun_size_mb elif lun_size_mb < 2000: snap_size_mb = 0.5 * lun_size_mb else: snap_size_mb = 0.2 * lun_size_mb snap_size_mb = int(math.ceil(snap_size_mb)) spec_dict = self._process_extra_specs(volume) try: selected_pool = self._get_storage_pool( volume, snap_size_mb, spec_dict['pool_type'], None) LOG.debug("Creating SRA of %(ssmb)sMB for lun of %(lsmb)sMB " "on %(vol_id)s", {'ssmb': snap_size_mb, 'lsmb': lun_size_mb, 'vol_id': volume_id}) except exception.ViolinResourceNotFound: raise except Exception: msg = _('No suitable storage pool found') LOG.exception(msg) raise exception.ViolinBackendErr(message=msg) res = self.vmem_mg.snapshot.create_snapshot_resource( lun=volume_id, size=snap_size_mb, enable_notification=False, policy=CONCERTO_DEFAULT_SRA_POLICY, enable_expansion=CONCERTO_DEFAULT_SRA_ENABLE_EXPANSION, expansion_threshold=CONCERTO_DEFAULT_SRA_EXPANSION_THRESHOLD, expansion_increment=CONCERTO_DEFAULT_SRA_EXPANSION_INCREMENT, expansion_max_size=CONCERTO_DEFAULT_SRA_EXPANSION_MAX_SIZE, enable_shrink=CONCERTO_DEFAULT_SRA_ENABLE_SHRINK, storage_pool_id=selected_pool['storage_pool_id']) if (not res['success']): msg = (_("Failed to create snapshot resource area on " "volume %(vol)s: %(res)s.") % {'vol': volume_id, 'res': res['msg']}) raise exception.VolumeBackendAPIException(data=msg)
def _list_volumes(self, req, body): """ Returns Cinder volume data for queries with Lunr kwargs filters :param req: python-cinderclient request :param body: python-cinderclient request's body {"list-volumes": {"node_id": "<node_id>"}} :return: {"count": <count>, "volumes": [ {<volume data 1st volume>}, {<volume data 2nd volume>}, ... ]} """ cinder_context = req.environ['cinder.context'] authorize_list_volumes(cinder_context) kwargs = SafeDict(body).get('list-volumes', {}) tenant_id = 'admin' lunr_client = lunrclient.client.LunrClient(tenant_id) data_name = "volumes" if 'node_id' in kwargs: lunr_node = lunr_except_handler( lambda: lunr_client.nodes.get(**kwargs)) hostname = lunr_node['cinder_host'] cinder_volumes = cinder_list_handler( volume_get_all_by_host(cinder_context, host=hostname), data_name) return cinder_volumes if 'restore_of' in kwargs: lunr_volumes = lunr_except_handler( lambda: lunr_client.volumes.list(**kwargs)) cinder_volumes_list = [] if len(lunr_volumes) > 0: for volume in lunr_volumes: if 'id' in volume: cinder_volumes_list.append( volume_get(cinder_context, volume_id=volume['id'])) if isinstance(cinder_volumes_list, list): cinder_volumes = { "count": len(cinder_volumes_list), data_name: cinder_volumes_list } else: cinder_volumes = {"count": 0, "volumes": cinder_volumes_list} return cinder_volumes elif 'id' in kwargs: cinder_volumes = cinder_list_handler( volume_get(cinder_context, volume_id=kwargs['id']), data_name) return cinder_volumes elif 'account_id' in kwargs: project_id = kwargs['account_id'] kwargs.clear() kwargs.update({'project_id': project_id}) cinder_volumes = cinder_list_handler( volume_get_all(cinder_context, marker=None, limit=None, sort_key='project_id', sort_dir='asc', filters=kwargs), data_name) return cinder_volumes else: cinder_volumes = cinder_list_handler( volume_get_all(cinder_context, marker=None, limit=None, sort_key='project_id', sort_dir='asc', filters=kwargs), data_name) return cinder_volumes
def _ensure_snapshot_resource_area(self, volume_id): """Make sure concerto snapshot resource area exists on volume. :param volume_id: Cinder volume ID corresponding to the backend LUN :raises: VolumeBackendAPIException: if cinder volume does not exist on backnd, or SRA could not be created. """ ctxt = context.get_admin_context() volume = api.volume_get(ctxt, volume_id) spec_dict = {} if not volume: msg = _("Failed to ensure snapshot resource area, could not " "locate volume for id %s") % volume_id raise exception.VolumeBackendAPIException(data=msg) if not self.vmem_mg.snapshot.lun_has_a_snapshot_resource(lun=volume_id): # Per Concerto documentation, the SRA size should be computed # as follows # Size-of-original-LUN Reserve for SRA # < 500MB 100% # 500MB to 2G 50% # >= 2G 20% # Note: cinder volume.size is in GB, vmemclient wants MB. lun_size_mb = volume["size"] * units.Ki if lun_size_mb < 500: snap_size_mb = lun_size_mb elif lun_size_mb < 2000: snap_size_mb = 0.5 * lun_size_mb else: snap_size_mb = 0.2 * lun_size_mb snap_size_mb = int(math.ceil(snap_size_mb)) spec_dict = self._process_extra_specs(volume) try: selected_pool = self._get_storage_pool(volume, snap_size_mb, spec_dict["pool_type"], None) LOG.debug( "Creating SRA of %(ssmb)sMB for lun of %(lsmb)sMB " "on %(vol_id)s", {"ssmb": snap_size_mb, "lsmb": lun_size_mb, "vol_id": volume_id}, ) except exception.ViolinResourceNotFound: raise except Exception: msg = _("No suitable storage pool found") LOG.exception(msg) raise exception.ViolinBackendErr(message=msg) res = self.vmem_mg.snapshot.create_snapshot_resource( lun=volume_id, size=snap_size_mb, enable_notification=False, policy=CONCERTO_DEFAULT_SRA_POLICY, enable_expansion=CONCERTO_DEFAULT_SRA_ENABLE_EXPANSION, expansion_threshold=CONCERTO_DEFAULT_SRA_EXPANSION_THRESHOLD, expansion_increment=CONCERTO_DEFAULT_SRA_EXPANSION_INCREMENT, expansion_max_size=CONCERTO_DEFAULT_SRA_EXPANSION_MAX_SIZE, enable_shrink=CONCERTO_DEFAULT_SRA_ENABLE_SHRINK, storage_pool_id=selected_pool["storage_pool_id"], ) if not res["success"]: msg = _("Failed to create snapshot resource area on " "volume %(vol)s: %(res)s.") % { "vol": volume_id, "res": res["msg"], } raise exception.VolumeBackendAPIException(data=msg)