Merge "Add ability to hide stacks based on tag"

This commit is contained in:
Jenkins 2015-04-10 03:26:02 +00:00 committed by Gerrit Code Review
commit f548b83951
11 changed files with 133 additions and 30 deletions

View File

@ -194,6 +194,11 @@ engine_opts = [
'HEAT_SIGNAL will allow calls to the Heat API '
'resource-signal using the provided keystone '
'credentials')),
cfg.ListOpt('hidden_stack_tags',
default=[],
help=_('Stacks containing these tag names will be hidden. '
'Multiple tags should be given in a comma-delimited '
'list (eg. hidden_stack_tags=hide_me,me_too).')),
cfg.StrOpt('onready',
help=_('Deprecated.')),
cfg.BoolOpt('stack_scheduler_hints',

View File

@ -142,10 +142,10 @@ def stack_get_by_name(context, stack_name):
def stack_get_all(context, limit=None, sort_keys=None, marker=None,
sort_dir=None, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
return IMPL.stack_get_all(context, limit, sort_keys,
marker, sort_dir, filters, tenant_safe,
show_deleted, show_nested)
show_deleted, show_nested, show_hidden)
def stack_get_all_by_owner_id(context, owner_id):
@ -153,11 +153,12 @@ def stack_get_all_by_owner_id(context, owner_id):
def stack_count_all(context, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
return IMPL.stack_count_all(context, filters=filters,
tenant_safe=tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested)
show_nested=show_nested,
show_hidden=show_hidden)
def stack_create(context, values):

View File

@ -34,6 +34,7 @@ from heat.db.sqlalchemy import models
from heat.rpc import api as rpc_api
CONF = cfg.CONF
CONF.import_opt('hidden_stack_tags', 'heat.common.config')
CONF.import_opt('max_events_per_stack', 'heat.common.config')
CONF.import_group('profiler', 'heat.common.config')
@ -398,7 +399,7 @@ def _paginate_query(context, query, model, limit=None, sort_keys=None,
def _query_stack_get_all(context, tenant_safe=True, show_deleted=False,
show_nested=False):
show_nested=False, show_hidden=False):
if show_nested:
query = soft_delete_aware_query(
context, models.Stack, show_deleted=show_deleted
@ -410,15 +411,22 @@ def _query_stack_get_all(context, tenant_safe=True, show_deleted=False,
if tenant_safe:
query = query.filter_by(tenant=context.tenant_id)
if not show_hidden:
query = query.filter(
~models.Stack.tags.any(
models.StackTag.tag.in_(cfg.CONF.hidden_stack_tags)))
return query
def stack_get_all(context, limit=None, sort_keys=None, marker=None,
sort_dir=None, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
query = _query_stack_get_all(context, tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested)
show_nested=show_nested,
show_hidden=show_hidden)
return _filter_and_page_query(context, query, limit, sort_keys,
marker, sort_dir, filters).all()
@ -440,10 +448,11 @@ def _filter_and_page_query(context, query, limit=None, sort_keys=None,
def stack_count_all(context, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
query = _query_stack_get_all(context, tenant_safe=tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested)
show_nested=show_nested,
show_hidden=show_hidden)
query = db_filters.exact_filter(query, models.Stack, filters)
return query.count()

View File

@ -315,7 +315,8 @@ class EngineService(service.Service):
admin_context = context.get_admin_context()
stacks = stack_object.Stack.get_all(
admin_context,
tenant_safe=False)
tenant_safe=False,
show_hidden=True)
for s in stacks:
self.stack_watch.start_watch_task(s.id, admin_context)
@ -466,7 +467,7 @@ class EngineService(service.Service):
@context.request_context
def list_stacks(self, cnxt, limit=None, marker=None, sort_keys=None,
sort_dir=None, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
"""
The list_stacks method returns attributes of all stacks. It supports
pagination (``limit`` and ``marker``), sorting (``sort_keys`` and
@ -481,17 +482,19 @@ class EngineService(service.Service):
:param tenant_safe: if true, scope the request by the current tenant
:param show_deleted: if true, show soft-deleted stacks
:param show_nested: if true, show nested stacks
:param show_hidden: if true, show hidden stacks
:returns: a list of formatted stacks
"""
stacks = parser.Stack.load_all(cnxt, limit, marker, sort_keys,
sort_dir, filters, tenant_safe,
show_deleted, resolve_data=False,
show_nested=show_nested)
show_nested=show_nested,
show_hidden=show_hidden)
return [api.format_stack(stack) for stack in stacks]
@context.request_context
def count_stacks(self, cnxt, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
"""
Return the number of stacks that match the given filters
:param cnxt: RPC context.
@ -499,6 +502,7 @@ class EngineService(service.Service):
:param tenant_safe: if true, scope the request by the current tenant
:param show_deleted: if true, count will include the deleted stacks
:param show_nested: if true, count will include nested stacks
:param show_hidden: if true, show hidden stacks
:returns: a integer representing the number of matched stacks
"""
return stack_object.Stack.count_all(
@ -506,7 +510,8 @@ class EngineService(service.Service):
filters=filters,
tenant_safe=tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested)
show_nested=show_nested,
show_hidden=show_hidden)
def _validate_deferred_auth_context(self, cnxt, stack):
if cfg.CONF.deferred_auth_method != 'password':

View File

@ -354,7 +354,7 @@ class Stack(collections.Mapping):
def load_all(cls, context, limit=None, marker=None, sort_keys=None,
sort_dir=None, filters=None, tenant_safe=True,
show_deleted=False, resolve_data=True,
show_nested=False):
show_nested=False, show_hidden=False):
stacks = stack_object.Stack.get_all(
context,
limit,
@ -364,7 +364,8 @@ class Stack(collections.Mapping):
filters,
tenant_safe,
show_deleted,
show_nested) or []
show_nested,
show_hidden) or []
for stack in stacks:
yield cls._from_db(context, stack, resolve_data=resolve_data)

View File

@ -91,7 +91,7 @@ class EngineClient(object):
def list_stacks(self, ctxt, limit=None, marker=None, sort_keys=None,
sort_dir=None, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
"""
The list_stacks method returns attributes of all stacks. It supports
pagination (``limit`` and ``marker``), sorting (``sort_keys`` and
@ -106,6 +106,7 @@ class EngineClient(object):
:param tenant_safe: if true, scope the request by the current tenant
:param show_deleted: if true, show soft-deleted stacks
:param show_nested: if true, show nested stacks
:param show_hidden: if true, show hidden stacks
:returns: a list of stacks
"""
return self.call(ctxt,
@ -114,10 +115,11 @@ class EngineClient(object):
sort_dir=sort_dir, filters=filters,
tenant_safe=tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested))
show_nested=show_nested,
show_hidden=show_hidden))
def count_stacks(self, ctxt, filters=None, tenant_safe=True,
show_deleted=False, show_nested=False):
show_deleted=False, show_nested=False, show_hidden=False):
"""
Return the number of stacks that match the given filters
:param ctxt: RPC context.
@ -125,13 +127,15 @@ class EngineClient(object):
:param tenant_safe: if true, scope the request by the current tenant
:param show_deleted: if true, count will include the deleted stacks
:param show_nested: if true, count will include nested stacks
:param show_hidden: if true, show hidden stacks
:returns: a integer representing the number of matched stacks
"""
return self.call(ctxt, self.make_msg('count_stacks',
filters=filters,
tenant_safe=tenant_safe,
show_deleted=show_deleted,
show_nested=show_nested))
show_nested=show_nested,
show_hidden=show_hidden))
def show_stack(self, ctxt, stack_identity):
"""

View File

@ -17,6 +17,7 @@ import uuid
import mock
import mox
from oslo_config import cfg
from oslo_utils import timeutils
import six
@ -552,6 +553,26 @@ class SqlAlchemyTest(common.HeatTestCase):
db_api.stack_get_all(self.ctx, sort_keys=sort_keys)
self.assertEqual(['id'], sort_keys)
def test_stack_get_all_hidden_tags(self):
cfg.CONF.set_override('hidden_stack_tags', ['hidden'])
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
stacks[0].tags = ['hidden']
stacks[0].store()
stacks[1].tags = ['random']
stacks[1].store()
st_db = db_api.stack_get_all(self.ctx, show_hidden=True)
self.assertEqual(3, len(st_db))
st_db_visible = db_api.stack_get_all(self.ctx, show_hidden=False)
self.assertEqual(2, len(st_db_visible))
# Make sure the hidden stack isn't in the stacks returned by
# stack_get_all_visible()
for stack in st_db_visible:
self.assertNotEqual(stacks[0].id, stack.id)
def test_stack_count_all(self):
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
@ -572,6 +593,21 @@ class SqlAlchemyTest(common.HeatTestCase):
st_db = db_api.stack_count_all(self.ctx, show_deleted=True)
self.assertEqual(3, st_db)
def test_count_all_hidden_tags(self):
cfg.CONF.set_override('hidden_stack_tags', ['hidden'])
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
stacks[0].tags = ['hidden']
stacks[0].store()
stacks[1].tags = ['random']
stacks[1].store()
st_db = db_api.stack_count_all(self.ctx, show_hidden=True)
self.assertEqual(3, st_db)
st_db_visible = db_api.stack_count_all(self.ctx, show_hidden=False)
self.assertEqual(2, st_db_visible)
def test_stack_count_all_with_filters(self):
self._setup_test_stack('foo', UUID1)
self._setup_test_stack('bar', UUID2)

View File

@ -161,7 +161,8 @@ class CfnStackControllerTest(common.HeatTestCase):
self.assertEqual(expected, result)
default_args = {'limit': None, 'sort_keys': None, 'marker': None,
'sort_dir': None, 'filters': None, 'tenant_safe': True,
'show_deleted': False, 'show_nested': False}
'show_deleted': False, 'show_nested': False,
'show_hidden': False}
mock_call.assert_called_once_with(
dummy_req.context, ('list_stacks', default_args))

View File

@ -385,7 +385,8 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
self.assertEqual(expected, result)
default_args = {'limit': None, 'sort_keys': None, 'marker': None,
'sort_dir': None, 'filters': None, 'tenant_safe': True,
'show_deleted': False, 'show_nested': False}
'show_deleted': False, 'show_nested': False,
'show_hidden': False}
mock_call.assert_called_once_with(
req.context, ('list_stacks', default_args))
@ -406,7 +407,7 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
rpc_call_args, _ = mock_call.call_args
engine_args = rpc_call_args[1][1]
self.assertEqual(8, len(engine_args))
self.assertEqual(9, len(engine_args))
self.assertIn('limit', engine_args)
self.assertIn('sort_keys', engine_args)
self.assertIn('marker', engine_args)
@ -664,7 +665,8 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
self.assertEqual(expected, result)
default_args = {'limit': None, 'sort_keys': None, 'marker': None,
'sort_dir': None, 'filters': None, 'tenant_safe': True,
'show_deleted': False, 'show_nested': False}
'show_deleted': False, 'show_nested': False,
'show_hidden': False}
mock_call.assert_called_once_with(
req.context, ('list_stacks', default_args))

View File

@ -1750,7 +1750,8 @@ class StackServiceTest(common.HeatTestCase):
self.eng.thread_group_mgr = None
self.eng.create_periodic_tasks()
mock_get_all.assert_called_once_with(mock.ANY, tenant_safe=False)
mock_get_all.assert_called_once_with(mock.ANY, tenant_safe=False,
show_hidden=True)
calls = start_watch_task.call_args_list
self.assertEqual(2, start_watch_task.call_count)
self.assertIn(mock.call(1, mock.ANY), calls)
@ -2057,6 +2058,7 @@ class StackServiceTest(common.HeatTestCase):
mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
)
@mock.patch.object(stack_object.Stack, 'get_all')
@ -2072,6 +2074,7 @@ class StackServiceTest(common.HeatTestCase):
mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
)
@mock.patch.object(stack_object.Stack, 'get_all')
@ -2086,6 +2089,7 @@ class StackServiceTest(common.HeatTestCase):
True,
mock.ANY,
mock.ANY,
mock.ANY,
)
@mock.patch.object(stack_object.Stack, 'get_all')
@ -2100,6 +2104,7 @@ class StackServiceTest(common.HeatTestCase):
False,
mock.ANY,
mock.ANY,
mock.ANY,
)
@mock.patch.object(stack_object.Stack, 'get_all')
@ -2114,6 +2119,7 @@ class StackServiceTest(common.HeatTestCase):
mock.ANY,
mock.ANY,
True,
mock.ANY,
)
@mock.patch.object(stack_object.Stack, 'get_all')
@ -2128,6 +2134,22 @@ class StackServiceTest(common.HeatTestCase):
mock.ANY,
True,
mock.ANY,
mock.ANY,
)
@mock.patch.object(stack_object.Stack, 'get_all')
def test_stack_list_show_hidden(self, mock_stack_get_all):
self.eng.list_stacks(self.ctx, show_hidden=True)
mock_stack_get_all.assert_called_once_with(mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
mock.ANY,
True,
)
@mock.patch.object(stack_object.Stack, 'count_all')
@ -2137,7 +2159,8 @@ class StackServiceTest(common.HeatTestCase):
filters={'foo': 'bar'},
tenant_safe=mock.ANY,
show_deleted=False,
show_nested=False)
show_nested=False,
show_hidden=False)
@mock.patch.object(stack_object.Stack, 'count_all')
def test_count_stacks_tenant_safe_default_true(self, mock_stack_count_all):
@ -2146,7 +2169,8 @@ class StackServiceTest(common.HeatTestCase):
filters=mock.ANY,
tenant_safe=True,
show_deleted=False,
show_nested=False)
show_nested=False,
show_hidden=False)
@mock.patch.object(stack_object.Stack, 'count_all')
def test_count_stacks_passes_tenant_safe_info(self, mock_stack_count_all):
@ -2155,7 +2179,8 @@ class StackServiceTest(common.HeatTestCase):
filters=mock.ANY,
tenant_safe=False,
show_deleted=False,
show_nested=False)
show_nested=False,
show_hidden=False)
@mock.patch.object(stack_object.Stack, 'count_all')
def test_count_stacks_show_nested(self, mock_stack_count_all):
@ -2164,7 +2189,8 @@ class StackServiceTest(common.HeatTestCase):
filters=mock.ANY,
tenant_safe=True,
show_deleted=False,
show_nested=True)
show_nested=True,
show_hidden=False)
@mock.patch.object(stack_object.Stack, 'count_all')
def test_count_stack_show_deleted(self, mock_stack_count_all):
@ -2173,7 +2199,18 @@ class StackServiceTest(common.HeatTestCase):
filters=mock.ANY,
tenant_safe=True,
show_deleted=True,
show_nested=False)
show_nested=False,
show_hidden=False)
@mock.patch.object(stack_object.Stack, 'count_all')
def test_count_stack_show_hidden(self, mock_stack_count_all):
self.eng.count_stacks(self.ctx, show_hidden=True)
mock_stack_count_all.assert_called_once_with(mock.ANY,
filters=mock.ANY,
tenant_safe=True,
show_deleted=False,
show_nested=False,
show_hidden=True)
@stack_context('service_abandon_stack')
def test_abandon_stack(self):

View File

@ -115,6 +115,7 @@ class EngineRpcAPITestCase(common.HeatTestCase):
'tenant_safe': mock.ANY,
'show_deleted': mock.ANY,
'show_nested': mock.ANY,
'show_hidden': mock.ANY,
}
self._test_engine_api('list_stacks', 'call', **default_args)
@ -124,6 +125,7 @@ class EngineRpcAPITestCase(common.HeatTestCase):
'tenant_safe': mock.ANY,
'show_deleted': mock.ANY,
'show_nested': mock.ANY,
'show_hidden': mock.ANY,
}
self._test_engine_api('count_stacks', 'call', **default_args)