From af853d479b70c22d60ae09e798ef4c3b62632fb2 Mon Sep 17 00:00:00 2001 From: wanghao Date: Mon, 9 Mar 2015 18:49:31 +0800 Subject: [PATCH] Fix response when querying host detail by host name When querying host detail by host name like 'wanghao-devstack-snapshot@lvmdriver-1' returned by host list command, cinder returns incorrect result in 'total' block. "resource": { "volume_count": "0", "total_volume_gb": "0", "total_snapshot_gb": "0", "project": "(total)", "host": "wanghao-devstack-snapshot@lvmdriver-1", "snapshot_count": "0" } This issue is caused by 'volume_data_get_for_host' in sqlalchemy. This has nothing to do with multibackend, this is due to the introduction of pool support for single backend. Fix this by querying volume filter by host or host name like 'host#%' in volume_data_get_for_host. Change-Id: I751a474677d50e552d87fe06fadfed45e3c1ddab Closes-Bug: #1429787 --- cinder/db/sqlalchemy/api.py | 12 +++++------ cinder/tests/unit/test_db_api.py | 36 +++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/cinder/db/sqlalchemy/api.py b/cinder/db/sqlalchemy/api.py index 17199ad99..bbf0cb072 100644 --- a/cinder/db/sqlalchemy/api.py +++ b/cinder/db/sqlalchemy/api.py @@ -1075,20 +1075,20 @@ def volume_create(context, values): @require_admin_context def volume_data_get_for_host(context, host, count_only=False): + host_attr = models.Volume.host + conditions = [host_attr == host, host_attr.op('LIKE')(host + '#%')] if count_only: result = model_query(context, func.count(models.Volume.id), - read_deleted="no").\ - filter_by(host=host).\ - first() + read_deleted="no").filter( + or_(*conditions)).first() return result[0] or 0 else: result = model_query(context, func.count(models.Volume.id), func.sum(models.Volume.size), - read_deleted="no").\ - filter_by(host=host).\ - first() + read_deleted="no").filter( + or_(*conditions)).first() # NOTE(vish): convert None to 0 return (result[0] or 0, result[1] or 0) diff --git a/cinder/tests/unit/test_db_api.py b/cinder/tests/unit/test_db_api.py index 85147ae9e..082572cfc 100644 --- a/cinder/tests/unit/test_db_api.py +++ b/cinder/tests/unit/test_db_api.py @@ -29,6 +29,10 @@ from cinder import test CONF = cfg.CONF +THREE = 3 +THREE_HUNDREDS = 300 +ONE_HUNDREDS = 100 + def _quota_reserve(context, project_id): """Create sample Quota, QuotaUsage and Reservation objects. @@ -264,23 +268,35 @@ class DBAPIVolumeTestCase(BaseTest): self.assertEqual(attachment['attached_host'], host_name) def test_volume_data_get_for_host(self): - for i in xrange(3): - for j in xrange(3): - db.volume_create(self.ctxt, {'host': 'h%d' % i, 'size': 100}) - for i in xrange(3): - self.assertEqual((3, 300), + for i in xrange(THREE): + for j in xrange(THREE): + db.volume_create(self.ctxt, {'host': 'h%d' % i, + 'size': ONE_HUNDREDS}) + for i in xrange(THREE): + self.assertEqual((THREE, THREE_HUNDREDS), db.volume_data_get_for_host( self.ctxt, 'h%d' % i)) + def test_volume_data_get_for_host_for_multi_backend(self): + for i in xrange(THREE): + for j in xrange(THREE): + db.volume_create(self.ctxt, {'host': + 'h%d@lvmdriver-1#lvmdriver-1' % i, + 'size': ONE_HUNDREDS}) + for i in xrange(THREE): + self.assertEqual((THREE, THREE_HUNDREDS), + db.volume_data_get_for_host( + self.ctxt, 'h%d@lvmdriver-1' % i)) + def test_volume_data_get_for_project(self): - for i in xrange(3): - for j in xrange(3): + for i in xrange(THREE): + for j in xrange(THREE): db.volume_create(self.ctxt, {'project_id': 'p%d' % i, - 'size': 100, + 'size': ONE_HUNDREDS, 'host': 'h-%d-%d' % (i, j), }) - for i in xrange(3): - self.assertEqual((3, 300), + for i in xrange(THREE): + self.assertEqual((THREE, THREE_HUNDREDS), db.volume_data_get_for_project( self.ctxt, 'p%d' % i))