Merge "Add execution controll option"

This commit is contained in:
Jenkins 2015-07-28 16:47:48 +00:00 committed by Gerrit Code Review
commit b04ee756d5
8 changed files with 144 additions and 17 deletions

View File

@ -58,6 +58,9 @@ core_opts = [
cfg.IntOpt('datasource_sync_period', default=0,
help='The number of seconds to wait between synchronizing '
'datasource config from the database '),
cfg.BoolOpt('enable_execute_action', default=True,
help="Sets the flag to False if you don't want the congress "
"to execute actions."),
]
# Register the configuration options

View File

@ -62,7 +62,8 @@ def create(rootdir, config_override=None):
name="engine",
moduleName="PolicyEngine",
description="Policy Engine (DseRuntime instance)",
args={'d6cage': cage, 'rootdir': src_path})
args={'d6cage': cage, 'rootdir': src_path,
'log_actions_only': cfg.CONF.enable_execute_action})
engine = cage.service_object('engine')
engine.initialize_table_subscriptions()
engine.debug_mode() # should take this out for production

View File

@ -1230,7 +1230,7 @@ class DseRuntime (Runtime, deepsix.deepSix):
self.d6cage = args['d6cage']
self.rootdir = args['rootdir']
self.policySubData = {}
self.log_actions_only = args.get('log_actions_only', False)
self.log_actions_only = args['log_actions_only']
def extend_schema(self, service_name, schema):
newschema = {}
@ -1360,6 +1360,12 @@ class DseRuntime (Runtime, deepsix.deepSix):
{'positional': ['p_arg1', 'p_arg2'],
'named': {'name1': 'n_arg1', 'name2': 'n_arg2'}}.
"""
if not self.log_actions_only:
LOG.info("action %s is called with args %s on %s, but "
"current configuration doesn't allow Congress to "
"execute any action.", action, action_args, service_name)
return
# Log the execution
LOG.info("%s:: executing: %s:%s on %s",
self.name, service_name, action, action_args)
@ -1378,8 +1384,7 @@ class DseRuntime (Runtime, deepsix.deepSix):
self.logger.info(
"Executing %s:%s(%s%s%s)",
service_name, action, pos_args, delimit, named_args)
if self.log_actions_only:
return
# execute the action on a service in the DSE
service = self.d6cage.service_object(service_name)
if not service:

View File

@ -298,7 +298,8 @@ class TestDataSourceDriver(base.TestCase):
cage.loadModule("PolicyDriver", helper.policy_module_path())
cage.createservice(name="policy", moduleName="PolicyDriver",
args={'d6cage': cage,
'rootdir': helper.data_module_path('')})
'rootdir': helper.data_module_path(''),
'log_actions_only': True})
args = helper.datasource_openstack_args()
args['poll_time'] = 0
args['client'] = neutron_client

View File

@ -198,7 +198,8 @@ class TestNovaDriver(base.TestCase):
cage.loadModule("PolicyDriver", helper.policy_module_path())
cage.createservice(name="policy", moduleName="PolicyDriver",
args={'d6cage': cage,
'rootdir': helper.data_module_path('')})
'rootdir': helper.data_module_path(''),
'log_actions_only': True})
cage.createservice(name="nova", moduleName="NovaDriver", args=args)
# Check that data gets sent from nova to policy as expected

View File

@ -48,7 +48,8 @@ class TestDSE(base.TestCase):
cage.createservice(name="data", moduleName="TestDriver",
args=helper.datasource_openstack_args())
cage.createservice(name="policy", moduleName="TestPolicy",
args={'d6cage': cage, 'rootdir': ''})
args={'d6cage': cage, 'rootdir': '',
'log_actions_only': True})
data = cage.services['data']['object']
policy = cage.services['policy']['object']
policy.subscribe('data', 'p', callback=policy.receive_msg)
@ -66,7 +67,8 @@ class TestDSE(base.TestCase):
cage.createservice(name="data", moduleName="TestDriver",
args=helper.datasource_openstack_args())
cage.createservice(name="policy", moduleName="TestPolicy",
args={'d6cage': cage, 'rootdir': ''})
args={'d6cage': cage, 'rootdir': '',
'log_actions_only': True})
data = cage.services['data']['object']
policy = cage.services['policy']['object']
# turn off module-schema syntax checking
@ -91,7 +93,8 @@ class TestDSE(base.TestCase):
cage.createservice(name="api", moduleName="TestDriver",
args=helper.datasource_openstack_args())
cage.createservice(name="policy", moduleName="TestPolicy",
args={'d6cage': cage, 'rootdir': ''})
args={'d6cage': cage, 'rootdir': '',
'log_actions_only': True})
data = cage.services['data']['object']
api = cage.services['api']['object']
policy = cage.services['policy']['object']
@ -134,7 +137,8 @@ class TestDSE(base.TestCase):
cage.createservice(name="data", moduleName="TestDriver",
args=helper.datasource_openstack_args())
cage.createservice(name="policy", moduleName="TestPolicy",
args={'d6cage': cage, 'rootdir': ''})
args={'d6cage': cage, 'rootdir': '',
'log_actions_only': True})
data = cage.services['data']['object']
policy = cage.services['policy']['object']
policy.create_policy('data')

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
import mock
from oslo_log import log as logging
from congress.datalog import base as datalog_base
@ -1265,13 +1266,27 @@ class TestSimulate(base.TestCase):
class TestActionExecution(base.TestCase):
class FakeCage(object):
def __init__(self, name):
self.name = name
def service_object(self, name):
if self.name == name:
return self
else:
return None
def test_insert_rule_insert_data(self):
args = {}
args['d6cage'] = None
args['d6cage'] = TestActionExecution.FakeCage('test')
args['rootdir'] = None
args['log_actions_only'] = True
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
run.create_policy('test')
run.debug_mode()
run.insert('execute[p(x)] :- q(x)')
@ -1280,13 +1295,24 @@ class TestActionExecution(base.TestCase):
self.assertEqual(len(run.logger.messages), 1, "No action logged")
self.assertEqual(run.logger.messages[0], 'Executing test:p(1)')
expected_args = ('test', 'p')
expected_kwargs = {'args': {'positional': [1]}}
args, kwargs = run.request.call_args_list[0]
self.assertEqual(expected_args, args)
self.assertEqual(expected_kwargs, kwargs)
def test_insert_data_insert_rule(self):
args = {}
args['d6cage'] = None
args['d6cage'] = TestActionExecution.FakeCage('test')
args['rootdir'] = None
args['log_actions_only'] = True
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
run.create_policy('test')
run.debug_mode()
run.insert('q(1)')
@ -1295,13 +1321,24 @@ class TestActionExecution(base.TestCase):
self.assertEqual(len(run.logger.messages), 1, "No action logged")
self.assertEqual(run.logger.messages[0], 'Executing test:p(1)')
expected_args = ('test', 'p')
expected_kwargs = {'args': {'positional': [1]}}
args, kwargs = run.request.call_args_list[0]
self.assertEqual(expected_args, args)
self.assertEqual(expected_kwargs, kwargs)
def test_insert_data_insert_rule_delete_data(self):
args = {}
args['d6cage'] = None
args['d6cage'] = TestActionExecution.FakeCage('test')
args['rootdir'] = None
args['log_actions_only'] = True
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
run.create_policy('test')
run.debug_mode()
run.insert('q(1)')
@ -1313,13 +1350,24 @@ class TestActionExecution(base.TestCase):
self.assertEqual(len(run.logger.messages), 1, "Delete failure")
self.assertEqual(run.logger.messages[0], 'Executing test:p(1)')
expected_args = ('test', 'p')
expected_kwargs = {'args': {'positional': [1]}}
args, kwargs = run.request.call_args_list[0]
self.assertEqual(expected_args, args)
self.assertEqual(expected_kwargs, kwargs)
def test_insert_data_insert_rule_delete_rule(self):
args = {}
args['d6cage'] = None
args['d6cage'] = TestActionExecution.FakeCage('test')
args['rootdir'] = None
args['log_actions_only'] = True
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
run.create_policy('test')
run.debug_mode()
run.insert('q(1)')
@ -1331,13 +1379,24 @@ class TestActionExecution(base.TestCase):
self.assertEqual(len(run.logger.messages), 1, "Delete failure")
self.assertEqual(run.logger.messages[0], 'Executing test:p(1)')
expected_args = ('test', 'p')
expected_kwargs = {'args': {'positional': [1]}}
args, kwargs = run.request.call_args_list[0]
self.assertEqual(expected_args, args)
self.assertEqual(expected_kwargs, kwargs)
def test_insert_data_insert_rule_noop_insert(self):
args = {}
args['d6cage'] = None
args['d6cage'] = TestActionExecution.FakeCage('test')
args['rootdir'] = None
args['log_actions_only'] = True
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
run.create_policy('test')
run.debug_mode()
run.insert('q(1)')
@ -1349,13 +1408,24 @@ class TestActionExecution(base.TestCase):
self.assertEqual(len(run.logger.messages), 1, "Delete failure")
self.assertEqual(run.logger.messages[0], 'Executing test:p(1)')
expected_args = ('test', 'p')
expected_kwargs = {'args': {'positional': [1]}}
args, kwargs = run.request.call_args_list[0]
self.assertEqual(expected_args, args)
self.assertEqual(expected_kwargs, kwargs)
def test_disjunction(self):
args = {}
args['d6cage'] = None
args['d6cage'] = TestActionExecution.FakeCage('test')
args['rootdir'] = None
args['log_actions_only'] = True
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
run.create_policy('test')
run.debug_mode()
run.insert('execute[p(x)] :- q(x)')
@ -1368,13 +1438,24 @@ class TestActionExecution(base.TestCase):
self.assertEqual(len(run.logger.messages), 1, "Delete failure")
self.assertEqual(run.logger.messages[0], 'Executing test:p(1)')
expected_args = ('test', 'p')
expected_kwargs = {'args': {'positional': [1]}}
args, kwargs = run.request.call_args_list[0]
self.assertEqual(expected_args, args)
self.assertEqual(expected_kwargs, kwargs)
def test_multiple_instances(self):
args = {}
args['d6cage'] = None
args['d6cage'] = TestActionExecution.FakeCage('test')
args['rootdir'] = None
args['log_actions_only'] = True
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
run.create_policy('test')
run.debug_mode()
run.insert('q(1)')
@ -1385,6 +1466,34 @@ class TestActionExecution(base.TestCase):
actualset = set([u'Executing test:p(1)', u'Executing test:p(2)'])
self.assertEqual(actualset, set(run.logger.messages))
expected_args_list = [
[('test', 'p'), {'args': {'positional': [1]}}],
[('test', 'p'), {'args': {'positional': [2]}}],
]
for args, kwargs in run.request.call_args_list:
self.assertTrue([args, kwargs] in expected_args_list)
expected_args_list.remove([args, kwargs])
def test_disabled_execute_action(self):
args = {}
args['d6cage'] = None
args['rootdir'] = None
args['log_actions_only'] = False
run = agnostic.DseRuntime(
name='test', keys='', inbox=None, datapath=None, args=args)
run.request = mock.Mock()
run.request.return_value = 'mocked request'
service_name = 'test-service'
action = 'non_executable_action'
action_args = {'positional': ['p_arg1'],
'named': {'key1': 'value1'}}
run.execute_action(service_name, action, action_args)
self.assertFalse(run.request.called)
class TestDelegation(base.TestCase):
"""Tests for Runtime's delegation functionality."""

View File

@ -44,6 +44,9 @@
# Seconds between polling database to sync datasources.
# datasource_sync_period = 60
# Flag to enable the congress to execute an action.
# enable_execute_action = True
[oslo_policy]
# The JSON file that defines policies.
policy_file = policy.json