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)
Exemple #3
0
    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)
Exemple #4
0
    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}
Exemple #5
0
    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}
Exemple #6
0
    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)
Exemple #7
0
    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
Exemple #9
0
    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)