Add volumes/summary API support
Add a new API to display volumes summary with total number of volumes and total size in GB (total_size: 500 and total_count: 20). DocImpact APIImpact Partially-Implements: blueprint display-volumes-summary-details Co-Authored-By: MR Swami Reddy <swamireddy@gmail.com> Change-Id: I0117a233afbd834a165ade9e1358f8dd38fbcfac
This commit is contained in:
parent
8da1781c18
commit
3db21d003f
@ -59,6 +59,7 @@ REST_API_VERSION_HISTORY = """
|
||||
* 3.9 - Add backup update interface.
|
||||
* 3.10 - Add group_id filter to list/detail volumes in _get_volumes.
|
||||
* 3.11 - Add group types and group specs API.
|
||||
* 3.12 - Add volumes summary API.
|
||||
|
||||
"""
|
||||
|
||||
@ -67,7 +68,7 @@ REST_API_VERSION_HISTORY = """
|
||||
# minimum version of the API supported.
|
||||
# Explicitly using /v1 or /v2 enpoints will still work
|
||||
_MIN_API_VERSION = "3.0"
|
||||
_MAX_API_VERSION = "3.11"
|
||||
_MAX_API_VERSION = "3.12"
|
||||
_LEGACY_API_VERSION1 = "1.0"
|
||||
_LEGACY_API_VERSION2 = "2.0"
|
||||
|
||||
|
@ -174,3 +174,7 @@ user documentation.
|
||||
3.11
|
||||
----
|
||||
Added group types and group specs API.
|
||||
|
||||
3.12
|
||||
----
|
||||
Added volumes/summary API.
|
||||
|
@ -53,7 +53,7 @@ class APIRouter(cinder.api.openstack.APIRouter):
|
||||
self.resources['volumes'] = volumes.create_resource(ext_mgr)
|
||||
mapper.resource("volume", "volumes",
|
||||
controller=self.resources['volumes'],
|
||||
collection={'detail': 'GET'},
|
||||
collection={'detail': 'GET', 'summary': 'GET'},
|
||||
member={'action': 'POST'})
|
||||
|
||||
self.resources['messages'] = messages.create_resource(ext_mgr)
|
||||
|
24
cinder/api/v3/views/volumes.py
Normal file
24
cinder/api/v3/views/volumes.py
Normal file
@ -0,0 +1,24 @@
|
||||
# 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.
|
||||
|
||||
|
||||
class ViewBuilder(object):
|
||||
"""Model a server API response as a python dictionary."""
|
||||
|
||||
def quick_summary(self, volume_count, volume_size):
|
||||
"""Number of volumes and size of volumes."""
|
||||
return {
|
||||
'volume-summary': {
|
||||
'total_count': volume_count,
|
||||
'total_size': volume_size
|
||||
},
|
||||
}
|
@ -16,8 +16,11 @@
|
||||
from cinder.api import common
|
||||
from cinder.api.openstack import wsgi
|
||||
from cinder.api.v2 import volumes as volumes_v2
|
||||
from cinder.api.v3.views import volumes as volume_views_v3
|
||||
from cinder import utils
|
||||
|
||||
SUMMARY_BASE_MICRO_VERSION = '3.12'
|
||||
|
||||
|
||||
class VolumeController(volumes_v2.VolumeController):
|
||||
"""The Volumes API controller for the OpenStack API V3."""
|
||||
@ -72,6 +75,19 @@ class VolumeController(volumes_v2.VolumeController):
|
||||
volumes = self._view_builder.summary_list(req, volumes)
|
||||
return volumes
|
||||
|
||||
@wsgi.Controller.api_version(SUMMARY_BASE_MICRO_VERSION)
|
||||
def summary(self, req):
|
||||
"""Return summary of volumes."""
|
||||
view_builder_v3 = volume_views_v3.ViewBuilder()
|
||||
context = req.environ['cinder.context']
|
||||
filters = req.params.copy()
|
||||
|
||||
utils.remove_invalid_filter_options(context, filters,
|
||||
self._get_volume_filter_options())
|
||||
|
||||
volumes = self.volume_api.get_volume_summary(context, filters=filters)
|
||||
return view_builder_v3.quick_summary(volumes[0], int(volumes[1]))
|
||||
|
||||
|
||||
def create_resource(ext_mgr):
|
||||
return wsgi.Resource(VolumeController(ext_mgr))
|
||||
|
@ -280,6 +280,16 @@ def volume_get_all_by_project(context, project_id, marker, limit,
|
||||
offset=offset)
|
||||
|
||||
|
||||
def get_volume_summary_all(context):
|
||||
"""Get all volume summary."""
|
||||
return IMPL.get_volume_summary_all(context)
|
||||
|
||||
|
||||
def get_volume_summary_by_project(context, project_id):
|
||||
"""Get all volume summary belonging to a project."""
|
||||
return IMPL.get_volume_summary_by_project(context, project_id)
|
||||
|
||||
|
||||
def volume_update(context, volume_id, values):
|
||||
"""Set the given properties on a volume and update it.
|
||||
|
||||
|
@ -1775,6 +1775,23 @@ def volume_get_all(context, marker, limit, sort_keys=None, sort_dirs=None,
|
||||
return query.all()
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def get_volume_summary_all(context):
|
||||
"""Retrieves all volumes summary.
|
||||
|
||||
:param context: context to query under
|
||||
:returns: volume summary of all projects
|
||||
"""
|
||||
query = model_query(context, func.count(models.Volume.id),
|
||||
func.sum(models.Volume.size), read_deleted="no")
|
||||
|
||||
if query is None:
|
||||
return []
|
||||
|
||||
result = query.first()
|
||||
return (result[0] or 0, result[1] or 0)
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def volume_get_all_by_host(context, host, filters=None):
|
||||
"""Retrieves all volumes hosted on a host.
|
||||
@ -2077,6 +2094,25 @@ def process_sort_params(sort_keys, sort_dirs, default_keys=None,
|
||||
return result_keys, result_dirs
|
||||
|
||||
|
||||
@require_context
|
||||
def get_volume_summary_by_project(context, project_id):
|
||||
"""Retrieves all volumes summary in a project.
|
||||
|
||||
:param context: context to query under
|
||||
:param project_id: project for all volumes being retrieved
|
||||
:returns: volume summary of a project
|
||||
"""
|
||||
query = model_query(context, func.count(models.Volume.id),
|
||||
func.sum(models.Volume.size), read_deleted="no").\
|
||||
filter_by(project_id=project_id)
|
||||
|
||||
if query is None:
|
||||
return []
|
||||
|
||||
result = query.first()
|
||||
return (result[0] or 0, result[1] or 0)
|
||||
|
||||
|
||||
@handle_db_data_error
|
||||
@require_context
|
||||
def volume_update(context, volume_id, values):
|
||||
|
@ -537,3 +537,13 @@ class VolumeList(base.ObjectListBase, base.CinderObject):
|
||||
expected_attrs = cls._get_expected_attrs(context)
|
||||
return base.obj_make_list(context, cls(context), objects.Volume,
|
||||
volumes, expected_attrs=expected_attrs)
|
||||
|
||||
@classmethod
|
||||
def get_volume_summary_all(cls, context):
|
||||
volumes = db.get_volume_summary_all(context)
|
||||
return volumes
|
||||
|
||||
@classmethod
|
||||
def get_volume_summary_by_project(cls, context, project_id):
|
||||
volumes = db.get_volume_summary_by_project(context, project_id)
|
||||
return volumes
|
||||
|
@ -128,7 +128,8 @@ class VolumeApiTest(test.TestCase):
|
||||
res_dict = self.controller.detail(req)
|
||||
self.assertTrue(mock_validate.called)
|
||||
|
||||
def _vol_in_request_body(self,
|
||||
@classmethod
|
||||
def _vol_in_request_body(cls,
|
||||
size=stubs.DEFAULT_VOL_SIZE,
|
||||
name=stubs.DEFAULT_VOL_NAME,
|
||||
description=stubs.DEFAULT_VOL_DESCRIPTION,
|
||||
|
@ -20,8 +20,10 @@ from cinder.api.openstack import api_version_request as api_version
|
||||
from cinder.api.v3 import volumes
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit.api.v2 import test_volumes as v2_test_volumes
|
||||
from cinder.tests.unit import fake_constants as fake
|
||||
from cinder.volume.api import API as vol_get
|
||||
|
||||
@ -145,3 +147,33 @@ class VolumeApiTest(test.TestCase):
|
||||
res_dict = self.controller.index(req)
|
||||
volumes = res_dict['volumes']
|
||||
self.assertEqual(2, len(volumes))
|
||||
|
||||
def _fake_volumes_summary_request(self, version='3.12'):
|
||||
req = fakes.HTTPRequest.blank('/v3/volumes/summary')
|
||||
req.headers = {'OpenStack-API-Version': 'volume ' + version}
|
||||
req.api_version_request = api_version.APIVersionRequest(version)
|
||||
return req
|
||||
|
||||
def test_volumes_summary_in_unsupport_version(self):
|
||||
"""Function call to test summary volumes API in unsupported version"""
|
||||
req = self._fake_volumes_summary_request(version='3.7')
|
||||
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||
self.controller.summary, req)
|
||||
|
||||
def test_volumes_summary_in_supported_version(self):
|
||||
"""Function call to test the summary volumes API for version v3."""
|
||||
req = self._fake_volumes_summary_request()
|
||||
res_dict = self.controller.summary(req)
|
||||
expected = {'volume-summary': {'total_size': 0.0, 'total_count': 0}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
vol = v2_test_volumes.VolumeApiTest._vol_in_request_body(
|
||||
availability_zone="nova")
|
||||
body = {"volume": vol}
|
||||
req = fakes.HTTPRequest.blank('/v3/volumes')
|
||||
res_dict = self.controller.create(req, body)
|
||||
|
||||
req = self._fake_volumes_summary_request()
|
||||
res_dict = self.controller.summary(req)
|
||||
expected = {'volume-summary': {'total_size': 1.0, 'total_count': 1}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
@ -523,6 +523,24 @@ class API(base.Base):
|
||||
LOG.info(_LI("Get all volumes completed successfully."))
|
||||
return volumes
|
||||
|
||||
def get_volume_summary(self, context, filters=None):
|
||||
check_policy(context, 'get_all')
|
||||
|
||||
if filters is None:
|
||||
filters = {}
|
||||
|
||||
allTenants = utils.get_bool_param('all_tenants', filters)
|
||||
|
||||
if context.is_admin and allTenants:
|
||||
del filters['all_tenants']
|
||||
volumes = objects.VolumeList.get_volume_summary_all(context)
|
||||
else:
|
||||
volumes = objects.VolumeList.get_volume_summary_by_project(
|
||||
context, context.project_id)
|
||||
|
||||
LOG.info(_LI("Get summary completed successfully."))
|
||||
return volumes
|
||||
|
||||
def get_snapshot(self, context, snapshot_id):
|
||||
check_policy(context, 'get_snapshot')
|
||||
snapshot = objects.Snapshot.get_by_id(context, snapshot_id)
|
||||
|
4
releasenotes/notes/volumes-summary-6b2485f339c88a91.yaml
Normal file
4
releasenotes/notes/volumes-summary-6b2485f339c88a91.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- A new API to display the volumes summary. This summary API displays the
|
||||
total number of volumes and total volume's size in GB.
|
Loading…
Reference in New Issue
Block a user