Merge "Add execution controll option"
This commit is contained in:
commit
b04ee756d5
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue