DB API: Pass columns_to_join to instance_get_active_by_window_joined

This makes the instance_get_active_by_window_joined database API
configurable for which columns should be joined from other tables,
similar to instance_get_all.

This lays the groundwork for the Instance object to pass expected_attrs
to the DB API for filtering which columns to load.

Partial-Bug: #1383469

Change-Id: I7089d732cbd06a854d47b7b9e4faf21b9ef498f1
This commit is contained in:
Matt Riedemann 2014-10-27 12:17:32 -07:00
parent 9736fc659c
commit 152767927c
3 changed files with 64 additions and 14 deletions

View File

@ -664,7 +664,8 @@ def instance_get_all_by_filters(context, filters, sort_key='created_at',
def instance_get_active_by_window_joined(context, begin, end=None,
project_id=None, host=None,
use_slave=False):
use_slave=False,
columns_to_join=None):
"""Get instances and joins active during a certain time window.
Specifying a project_id will filter for a certain project.
@ -672,7 +673,8 @@ def instance_get_active_by_window_joined(context, begin, end=None,
"""
return IMPL.instance_get_active_by_window_joined(context, begin, end,
project_id, host,
use_slave=use_slave)
use_slave=use_slave,
columns_to_join=columns_to_join)
def instance_get_all_by_host(context, host,

View File

@ -2145,14 +2145,22 @@ def process_sort_params(sort_keys, sort_dirs,
@require_context
def instance_get_active_by_window_joined(context, begin, end=None,
project_id=None, host=None,
use_slave=False):
use_slave=False,
columns_to_join=None):
"""Return instances and joins that were active during window."""
session = get_session(use_slave=use_slave)
query = session.query(models.Instance)
query = query.options(joinedload('info_cache')).\
options(joinedload('security_groups')).\
filter(or_(models.Instance.terminated_at == null(),
if columns_to_join is None:
columns_to_join = ['info_cache', 'security_groups']
manual_joins = ['metadata', 'system_metadata']
else:
manual_joins, columns_to_join = _manual_join_columns(columns_to_join)
for column in columns_to_join:
query = query.options(joinedload(column))
query = query.filter(or_(models.Instance.terminated_at == null(),
models.Instance.terminated_at > begin))
if end:
query = query.filter(models.Instance.launched_at < end)
@ -2161,7 +2169,7 @@ def instance_get_active_by_window_joined(context, begin, end=None,
if host:
query = query.filter_by(host=host)
return _instances_fill_metadata(context, query.all())
return _instances_fill_metadata(context, query.all(), manual_joins)
def _instance_get_all_query(context, project_only=False,

View File

@ -727,25 +727,65 @@ class SqlAlchemyDbApiTestCase(DbTestCase):
now2 = now + datetime.timedelta(minutes=2)
now3 = now + datetime.timedelta(minutes=3)
ctxt = context.get_admin_context()
self.create_instance_with_args(launched_at=now)
self.create_instance_with_args(launched_at=now1, terminated_at=now2)
self.create_instance_with_args(launched_at=now2, terminated_at=now3)
self.create_instance_with_args(launched_at=now3, terminated_at=None)
# used for testing columns_to_join
network_info = jsonutils.dumps({'ckey': 'cvalue'})
sample_data = {
'metadata': {'mkey1': 'mval1', 'mkey2': 'mval2'},
'system_metadata': {'smkey1': 'smval1', 'smkey2': 'smval2'},
'info_cache': {'network_info': network_info},
}
self.create_instance_with_args(launched_at=now, **sample_data)
self.create_instance_with_args(launched_at=now1, terminated_at=now2,
**sample_data)
self.create_instance_with_args(launched_at=now2, terminated_at=now3,
**sample_data)
self.create_instance_with_args(launched_at=now3, terminated_at=None,
**sample_data)
result = sqlalchemy_api.instance_get_active_by_window_joined(
ctxt, begin=now)
self.assertEqual(4, len(result))
# verify that all default columns are joined
meta = utils.metadata_to_dict(result[0]['metadata'])
self.assertEqual(sample_data['metadata'], meta)
sys_meta = utils.metadata_to_dict(result[0]['system_metadata'])
self.assertEqual(sample_data['system_metadata'], sys_meta)
self.assertIn('info_cache', result[0])
result = sqlalchemy_api.instance_get_active_by_window_joined(
ctxt, begin=now3)
ctxt, begin=now3, columns_to_join=['info_cache'])
self.assertEqual(2, len(result))
# verify that only info_cache is loaded
meta = utils.metadata_to_dict(result[0]['metadata'])
self.assertEqual({}, meta)
self.assertIn('info_cache', result[0])
result = sqlalchemy_api.instance_get_active_by_window_joined(
ctxt, begin=start_time, end=now)
self.assertEqual(0, len(result))
result = sqlalchemy_api.instance_get_active_by_window_joined(
ctxt, begin=start_time, end=now2)
ctxt, begin=start_time, end=now2,
columns_to_join=['system_metadata'])
self.assertEqual(2, len(result))
# verify that only system_metadata is loaded
meta = utils.metadata_to_dict(result[0]['metadata'])
self.assertEqual({}, meta)
sys_meta = utils.metadata_to_dict(result[0]['system_metadata'])
self.assertEqual(sample_data['system_metadata'], sys_meta)
self.assertNotIn('info_cache', result[0])
result = sqlalchemy_api.instance_get_active_by_window_joined(
ctxt, begin=now2, end=now3)
ctxt, begin=now2, end=now3,
columns_to_join=['metadata', 'info_cache'])
self.assertEqual(2, len(result))
# verify that only metadata and info_cache are loaded
meta = utils.metadata_to_dict(result[0]['metadata'])
self.assertEqual(sample_data['metadata'], meta)
sys_meta = utils.metadata_to_dict(result[0]['system_metadata'])
self.assertEqual({}, sys_meta)
self.assertIn('info_cache', result[0])
self.assertEqual(network_info, result[0]['info_cache']['network_info'])
class ProcessSortParamTestCase(test.TestCase):