def test_module_schemas(self):
        """Test that rules are properly checked against module schemas."""

        modules = compile.ModuleSchemas(
            {'mod1': compile.Schema({'p': (1, 2, 3), 'q': (1,)}),
             'mod2': compile.Schema({'p': (1,), 'q': (1, 2)})})

        def check_err(code_string, emsg, msg, f=compile.rule_errors):
            rule = compile.parse1(code_string)
            errs = f(rule, modules)
            self.assertTrue(any(emsg in str(err) for err in errs),
                    msg + ":: Failed to find error message '" + emsg +
                    "' in: " + ";".join(str(e) for e in errs))

        # no errors
        rule = compile.parse1('p(x) :- q(x), mod1:p(x, y, z), mod2:q(x, y), '
                              'mod1:q(t), mod2:p(t)')
        errs = compile.rule_errors(rule, modules)
        self.assertEqual(len(errs), 0, "Should not have found any errors")

        # unknown module
        check_err('p(x) :- q(x), mod3:q(x), r(x)',
                  'unknown module',
                  'Unknown module for rule')

        # unknown table within module
        check_err('p(x) :- q(x), mod1:r(x), r(x)',
                  'unknown table',
                  'Unknown table for rule')

        # wrong number of arguments
        check_err('p(x) :- q(x), mod1:p(x,y,z,w), r(x)',
                  'only 3 arguments are permitted',
                  'Wrong number of arguments for rule')

        # same tests for an atom

        # no errors
        atom = compile.parse1('mod1:p(1, 2, 2)')
        errs = compile.fact_errors(atom, modules)
        self.assertEqual(len(errs), 0, "Should not have found any errors")

        # unknown module
        check_err('mod3:q(1)',
                  'unknown module',
                  'Unknown module for atom',
                  f=compile.fact_errors)

        # unknown table within module
        check_err('mod1:r(1)',
                  'unknown table',
                  'Unknown table for atom',
                  f=compile.fact_errors)

        # wrong number of arguments
        check_err('mod1:p(1, 2, 3, 4)',
                  'only 3 arguments are permitted',
                  'Wrong number of arguments for atom',
                  f=compile.fact_errors)
Exemple #2
0
 def check(self, input_string, correct_string, msg):
     rule = compile.parse1(input_string)
     actual = compile.reorder_for_safety(rule)
     correct = compile.parse1(correct_string)
     if correct != actual:
         emsg = "Correct: " + str(correct)
         emsg += "; Actual: " + str(actual)
         self.fail(msg + " :: " + emsg)
Exemple #3
0
 def check(self, input_string, correct_string, msg):
     rule = compile.parse1(input_string)
     actual = compile.reorder_for_safety(rule)
     correct = compile.parse1(correct_string)
     if correct != actual:
         emsg = "Correct: " + str(correct)
         emsg += "; Actual: " + str(actual)
         self.fail(msg + " :: " + emsg)
Exemple #4
0
    def test_discard_rules_with_same_head(self):
        rule1 = compile.parse1('p(x,y) :- q(x), r(y)')
        rule2 = compile.parse1('p(x,y) :- s(x), t(y)')
        self.assertTrue(self.ruleset.add_rule('p', rule1))
        self.assertTrue(self.ruleset.add_rule('p', rule2))
        self.assertTrue('p' in self.ruleset)
        self.assertTrue(rule1 in self.ruleset.get_rules('p'))
        self.assertTrue(rule2 in self.ruleset.get_rules('p'))

        self.assertTrue(self.ruleset.discard_rule('p', rule1))
        self.assertTrue(self.ruleset.discard_rule('p', rule2))
        self.assertFalse('p' in self.ruleset)
        self.assertEqual([], self.ruleset.keys())
Exemple #5
0
    def test_rule_api_model(self):
        """Test the rule api model.  Same as test_multiple except
        we use the api interface instead of the DSE interface.
        """
        api = self.api
        cage = self.cage
        engine = self.engine

        # Insert formula (which creates neutron services)
        net_formula = create_networkXnetwork_group('p')
        LOG.debug("Sending formula: {}".format(str(net_formula)))
        engine.debug_mode()
        context = {'policy_id': engine.DEFAULT_THEORY}
        (id1, rule) = api['rule'].add_item(
            {'rule': str(net_formula)}, {}, context=context)
        # Poll
        neutron = cage.service_object('neutron')
        neutron2 = cage.service_object('neutron2')
        neutron.poll()
        neutron2.poll()
        helper.pause()
        # Insert a second formula
        other_formula = compile.parse1('q(x,y) :- p(x,y)')
        (id2, rule) = api['rule'].add_item(
            {'rule': str(other_formula)}, {}, context=context)
        helper.pause()  # give time for messages/creation of services
        ans1 = ('p("240ff9df-df35-43ae-9df5-27fae87f2492",  '
                '  "240ff9df-df35-43ae-9df5-27fae87f2492") ')
        ans2 = ('q("240ff9df-df35-43ae-9df5-27fae87f2492",  '
                '  "240ff9df-df35-43ae-9df5-27fae87f2492") ')
        e = helper.db_equal(engine.select('p(x,y)'), ans1)
        self.assertTrue(e, "Insert rule-api 1")
        e = helper.db_equal(engine.select('q(x,y)'), ans2)
        self.assertTrue(e, "Insert rule-api 2")
        # Get formula
        ruleobj = api['rule'].get_item(id1, {}, context=context)
        self.assertTrue(e, net_formula == compile.parse1(ruleobj['rule']))
        # Get all formulas
        ds = api['rule'].get_items({}, context=context)['results']
        self.assertEqual(len(ds), 2)
        ids = set([x['id'] for x in ds])
        rules = set([compile.parse1(x['rule']) for x in ds])
        self.assertEqual(ids, set([id1, id2]))
        self.assertEqual(rules, set([net_formula, other_formula]))
        # Delete formula
        api['rule'].delete_item(id1, {}, context=context)
        # Get all formulas
        ds = api['rule'].get_items({}, context=context)['results']
        self.assertEqual(len(ds), 1)
        ids = sorted([x['id'] for x in ds])
        self.assertEqual(ids, sorted([id2]))
Exemple #6
0
    def test_add_rules_with_different_head(self):
        rule1 = compile.parse1('p1(x,y) :- q(x), r(y)')
        rule2 = compile.parse1('p2(x,y) :- s(x), t(y)')

        self.assertTrue(self.ruleset.add_rule('p1', rule1))
        self.assertTrue(self.ruleset.add_rule('p2', rule2))

        self.assertTrue('p1' in self.ruleset)
        self.assertEqual([rule1], self.ruleset.get_rules('p1'))
        self.assertTrue('p1' in self.ruleset.keys())

        self.assertTrue('p2' in self.ruleset)
        self.assertEqual([rule2], self.ruleset.get_rules('p2'))
        self.assertTrue('p2' in self.ruleset.keys())
    def test_rule_api_model(self):
        """Test the rule api model.  Same as test_multiple except
        we use the api interface instead of the DSE interface.
        """
        api = self.api
        cage = self.cage
        engine = self.engine

        # Insert formula
        net_formula = create_networkXnetwork_group('p')
        LOG.debug("Sending formula: %s", net_formula)
        engine.debug_mode()
        context = {'policy_id': engine.DEFAULT_THEORY}
        (id1, rule) = api['rule'].add_item(
            {'rule': str(net_formula)}, {}, context=context)
        # Poll
        neutron = cage.service_object('neutron')
        neutron2 = cage.service_object('neutron2')
        neutron.poll()
        neutron2.poll()
        # Insert a second formula
        other_formula = compile.parse1('q(x,y) :- p(x,y)')
        (id2, rule) = api['rule'].add_item(
            {'rule': str(other_formula)}, {}, context=context)
        ans1 = ('p("240ff9df-df35-43ae-9df5-27fae87f2492",  '
                '  "240ff9df-df35-43ae-9df5-27fae87f2492") ')
        ans2 = ('q("240ff9df-df35-43ae-9df5-27fae87f2492",  '
                '  "240ff9df-df35-43ae-9df5-27fae87f2492") ')
        # Wait for first query so messages can be delivered.
        #    But once the p table has its data, no need to wait anymore.
        helper.retry_check_db_equal(engine, 'p(x,y)', ans1)
        e = helper.db_equal(engine.select('q(x,y)'), ans2)
        self.assertTrue(e, "Insert rule-api 2")
        # Get formula
        ruleobj = api['rule'].get_item(id1, {}, context=context)
        self.assertTrue(e, net_formula == compile.parse1(ruleobj['rule']))
        # Get all formulas
        ds = api['rule'].get_items({}, context=context)['results']
        self.assertEqual(len(ds), 2)
        ids = set([x['id'] for x in ds])
        rules = set([compile.parse1(x['rule']) for x in ds])
        self.assertEqual(ids, set([id1, id2]))
        self.assertEqual(rules, set([net_formula, other_formula]))
        # Delete formula
        api['rule'].delete_item(id1, {}, context=context)
        # Get all formulas
        ds = api['rule'].get_items({}, context=context)['results']
        self.assertEqual(len(ds), 1)
        ids = sorted([x['id'] for x in ds])
        self.assertEqual(ids, sorted([id2]))
Exemple #8
0
 def check_err(self, input_string, unsafe_lit_strings, msg):
     rule = compile.parse1(input_string)
     try:
         compile.reorder_for_safety(rule)
         self.fail("Failed to raise exception for " + input_string)
     except compile.CongressException as e:
         errmsg = str(e)
         # parse then print to string so string rep same in err msg
         unsafe_lits = [str(compile.parse1(x)) for x in unsafe_lit_strings]
         missing_lits = [m for m in unsafe_lits
                         if m + " (vars" not in errmsg]
         if len(missing_lits) > 0:
             self.fail(
                 "Unsafe literals {} not reported in error: {}".format(
                     ";".join(missing_lits), errmsg))
Exemple #9
0
    def add_item(self, item, id_=None, context=None):
        """Add item to model.

        Args:
            item: The item to add to the model
            id_: The ID of the item, or None if an ID should be generated
            context: Key-values providing frame of reference of request

        Returns:
             Tuple of (ID, newly_created_item)

        Raises:
            KeyError: ID already exists.
        """
        # TODO(thinrichs): add comment property to rule
        if id_ is not None:
            raise NotImplemented
        str_rule = item['rule']
        rule = compile.parse1(str_rule)
        changes = self.change_rule(rule, context)
        for change in changes:
            if change.formula == rule:
                d = {'rule': str(rule),
                     'id': rule.id,
                     'comment': None}
                return (rule.id, d)
        # rule already existed
        policy_name = self.policy_name(context)
        for p in self.engine.theory[policy_name].policy():
            if p == rule:
                d = {'rule': str(rule),
                     'id': rule.id,
                     'comment': 'None'}
                return (rule.id, d)
        raise Exception("add_item added a rule but then could not find it.")
Exemple #10
0
 def check_err(self, input_string, unsafe_lit_strings, msg):
     rule = compile.parse1(input_string)
     try:
         compile.reorder_for_safety(rule)
         self.fail("Failed to raise exception for " + input_string)
     except compile.CongressException as e:
         errmsg = str(e)
         # parse then print to string so string rep same in err msg
         unsafe_lits = [str(compile.parse1(x)) for x in unsafe_lit_strings]
         missing_lits = [
             m for m in unsafe_lits if m + " (vars" not in errmsg
         ]
         if len(missing_lits) > 0:
             self.fail(
                 "Unsafe literals {} not reported in error: {}".format(
                     ";".join(missing_lits), errmsg))
    def test_error_checking(self):
        """Test error-checking on insertion of rules."""
        code = "p(x) :- q(x)"
        run = self.prep_runtime(code)
        result = run.get_target(MAT_THEORY).policy()
        self.assertTrue(len(result) == 1)
        self.assertTrue(compile.parse1("p(x) :- q(x)") in result)

        # safety 1
        code = "p(x) :- not q(x)"
        run = self.prep_runtime("", "** Safety 1 **")
        permitted, changes = run.insert(code, MAT_THEORY)
        self.assertFalse(permitted)

        # safety 2
        code = "p(x) :- q(y)"
        run = self.prep_runtime("", "** Safety 2 **")
        permitted, changes = run.insert(code, MAT_THEORY)
        self.assertFalse(permitted)

        # recursion into classification theory
        code = "p(x) :- p(x)"
        run = self.prep_runtime("", "** Classification Recursion **")
        permitted, changes = run.insert(code, MAT_THEORY)
        self.assertTrue(permitted)

        # stratification into classification theory
        code = "p(x) :- q(x), not p(x)"
        run = self.prep_runtime("", "** Classification Stratification **")
        permitted, changes = run.insert(code, MAT_THEORY)
        self.assertFalse(permitted)
Exemple #12
0
    def test_error_checking(self):
        """Test error-checking on insertion of rules."""
        code = ("p(x) :- q(x)")
        run = self.prep_runtime(code)
        result = run.get_target(MAT_THEORY).policy()
        self.assertTrue(len(result) == 1)
        self.assertTrue(compile.parse1("p(x) :- q(x)") in result)

        # safety 1
        code = ("p(x) :- not q(x)")
        run = self.prep_runtime("", "** Safety 1 **")
        permitted, changes = run.insert(code, MAT_THEORY)
        self.assertFalse(permitted)

        # safety 2
        code = ("p(x) :- q(y)")
        run = self.prep_runtime("", "** Safety 2 **")
        permitted, changes = run.insert(code, MAT_THEORY)
        self.assertFalse(permitted)

        # TODO(thinrichs): weaken cross-policy recursion restriction
        #   so that we can include recursion within a single theory.
        # recursion into classification theory
        # code = ("p(x) :- p(x)")
        # run = self.prep_runtime("", "** Classification Recursion **")
        # permitted, changes = run.insert(code, MAT_THEORY)
        # self.assertTrue(permitted)

        # stratification into classification theory
        code = ("p(x) :- q(x), not p(x)")
        run = self.prep_runtime("", "** Classification Stratification **")
        permitted, changes = run.insert(code, MAT_THEORY)
        self.assertFalse(permitted)
Exemple #13
0
    def test_clear_ruleset(self):
        rule1 = compile.parse1('p(x,y) :- q(x), r(y)')
        self.ruleset.add_rule('p', rule1)
        self.ruleset.clear()

        self.assertFalse('p' in self.ruleset)
        self.assertEqual([], self.ruleset.keys())
 def check_err(code_string, theory, emsg, msg, f=compile.rule_errors):
     rule = compile.parse1(code_string)
     errs = f(rule, run.theory, theory)
     self.assertTrue(
         any(emsg in str(err) for err in errs),
         msg + ":: Failed to find error message '" + emsg + "' in: " +
         ";".join(str(e) for e in errs))
Exemple #15
0
    def test_discard_rule(self):
        rule1 = compile.parse1('p(x,y) :- q(x), r(y)')
        self.assertTrue(self.ruleset.add_rule('p', rule1))
        self.assertTrue('p' in self.ruleset)
        self.assertEqual([rule1], self.ruleset.get_rules('p'))

        self.assertTrue(self.ruleset.discard_rule('p', rule1))
        self.assertFalse('p' in self.ruleset)
        self.assertEqual([], self.ruleset.keys())
Exemple #16
0
 def test_policy_tables(self):
     """Test basic DSE functionality with policy engine and the API."""
     cage = congress.dse.d6cage.d6Cage()
     # so that we exit once test finishes; all other threads are forced
     #    to be daemons
     cage.daemon = True
     cage.start()
     cage.loadModule("TestDriver",
                     helper.data_module_path("test_driver.py"))
     cage.loadModule("TestPolicy", helper.policy_module_path())
     cage.createservice(name="data", moduleName="TestDriver",
                        args=helper.datasource_openstack_args())
     # using regular testdriver as API for now
     cage.createservice(name="api", moduleName="TestDriver",
                        args=helper.datasource_openstack_args())
     cage.createservice(name="policy", moduleName="TestPolicy",
                        args={'d6cage': cage, 'rootdir': ''})
     data = cage.services['data']['object']
     api = cage.services['api']['object']
     policy = cage.services['policy']['object']
     policy.subscribe('api', 'policy-update',
                      callback=policy.receive_policy_update)
     # simulate API call for insertion of policy statements
     formula = compile.parse1('p(x) :- data:q(x)')
     api.publish('policy-update', [runtime.Event(formula)])
     helper.pause()
     # simulate data source publishing to q
     formula = compile.parse1('q(1)')
     data.publish('q', [runtime.Event(formula)])
     helper.pause()  # give other threads chance to run
     # check that policy did the right thing with data
     e = helper.db_equal(policy.select('data:q(x)'), 'data:q(1)')
     self.assertTrue(e, 'Policy insert 1')
     e = helper.db_equal(policy.select('p(x)'), 'p(1)')
     self.assertTrue(e, 'Policy insert 2')
     #check that publishing into 'p' does not work
     formula = compile.parse1('p(3)')
     data.publish('p', [runtime.Event(formula)])
     helper.pause()
     e = helper.db_equal(policy.select('p(x)'), 'p(1)')
     self.assertTrue(e, 'Policy noninsert')
    def test_rule_validation(self):
        """Test that rules are properly validated."""
        # unsafe var in head
        rule = compile.parse1('p(x) :- q(y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(errs), 1)

        # multiple unsafe vars in head
        rule = compile.parse1('p(x,y,z) :- q(w)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 3)

        # unsafe var in negtative literal:
        rule = compile.parse1('p(x) :- q(x), not r(y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)

        # unsafe var in negative literal: ensure head doesn't make safe
        rule = compile.parse1('p(x) :- not q(x)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)

        # unsafe var in negative literal:
        #      ensure partial safety not total safety
        rule = compile.parse1('p(x) :- q(x), not r(x,y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)

        # unsafe var in negative literal: ensure double negs doesn't make safe
        rule = compile.parse1('p(x) :- q(x), not r(x,y), not s(x, y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)
Exemple #18
0
    def test_rule_validation(self):
        """Test that rules are properly validated."""
        # unsafe var in head
        rule = compile.parse1('p(x) :- q(y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(errs), 1)

        # multiple unsafe vars in head
        rule = compile.parse1('p(x,y,z) :- q(w)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 3)

        # unsafe var in negtative literal:
        rule = compile.parse1('p(x) :- q(x), not r(y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)

        # unsafe var in negative literal: ensure head doesn't make safe
        rule = compile.parse1('p(x) :- not q(x)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)

        # unsafe var in negative literal:
        #      ensure partial safety not total safety
        rule = compile.parse1('p(x) :- q(x), not r(x,y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)

        # unsafe var in negative literal: ensure double negs doesn't make safe
        rule = compile.parse1('p(x) :- q(x), not r(x,y), not s(x, y)')
        errs = compile.rule_errors(rule)
        self.assertEqual(len(set([str(x) for x in errs])), 1)
Exemple #19
0
    def get_items(self, context=None):
        """Get items in model.

        Args:
            context: Key-values providing frame of reference of request

        Returns: A tuple (id, item) for all items in model.
        """
        LOG.info("get_items(context=%s)", str(context))
        if context['ds_id'] in self.engine.theory:
            tablename = context['table_id']
            arity = self.engine.theory[context['ds_id']].get_arity(tablename)
            if arity is None:
                return []
            args = ["x" + str(i) for i in xrange(0, arity)]
            query = compile.parse1(tablename + "(" + ",".join(args) + ")")
            LOG.info("query: " + str(query))
            literals = self.engine.theory[context['ds_id']].select(query)
        else:
            tablename = context['ds_id'] + ":" + context['table_id']
            arity = self.engine.theory[
                self.engine.theory.DATABASE].get_arity(tablename)
            if arity is None:
                return []
            args = ["x" + str(i) for i in xrange(0, arity)]
            query = compile.parse1(tablename + "(" + ",".join(args) + ")")
            LOG.info("query: " + str(query))
            literals = self.engine.theory[
                self.engine.theory.DATABASE].select(query)

        result = []
        for lit in literals:
            d = {}
            d['data'] = [arg.name for arg in lit.arguments]
            # tuples don't have IDs for now.  Could hash them I suppose.
            #  But if you're trying to use an ID you're doing
            #  something wrong.
            result.append((None, d))
        return result
Exemple #20
0
 def test_policy_tables(self):
     """Test basic DSE functionality with policy engine and the API."""
     cage = congress.dse.d6cage.d6Cage()
     cage.loadModule("TestDriver",
                     helper.data_module_path("test_driver.py"))
     cage.loadModule("TestPolicy", helper.policy_module_path())
     cage.createservice(name="data", moduleName="TestDriver",
                        args=helper.datasource_openstack_args())
     # using regular testdriver as API for now
     cage.createservice(name="api", moduleName="TestDriver",
                        args=helper.datasource_openstack_args())
     cage.createservice(name="policy", moduleName="TestPolicy",
                        args={'d6cage': cage, 'rootdir': ''})
     data = cage.services['data']['object']
     api = cage.services['api']['object']
     policy = cage.services['policy']['object']
     policy.set_schema('data', compile.Schema({'q': (1,)}))
     policy.subscribe('api', 'policy-update',
                      callback=policy.receive_policy_update)
     # simulate API call for insertion of policy statements
     formula = compile.parse1('p(x) :- data:q(x)')
     api.publish('policy-update', [runtime.Event(formula)])
     helper.retry_check_nonempty_last_policy_change(policy)
     # simulate data source publishing to q
     formula = compile.parse1('q(1)')
     data.publish('q', [runtime.Event(formula)])
     helper.retry_check_db_equal(policy, 'data:q(x)', 'data:q(1)')
     # check that policy did the right thing with data
     e = helper.db_equal(policy.select('p(x)'), 'p(1)')
     self.assertTrue(e, 'Policy insert')
     # check that publishing into 'p' does not work
     formula = compile.parse1('p(3)')
     data.publish('p', [runtime.Event(formula)])
     # can't actually check that the update for p does not arrive
     # so instead wait a bit and check
     helper.pause()
     e = helper.db_equal(policy.select('p(x)'), 'p(1)')
     self.assertTrue(e, 'Policy non-insert')
Exemple #21
0
def create_network_group(tablename):
    """Return rule of the form TABLENAME(x) :- neutron:network(..., x, ...)
    """
    network_key_to_index = NeutronDriver.get_column_map(
        NeutronDriver.NETWORKS)
    network_id_index = network_key_to_index['id']
    network_max_index = max(network_key_to_index.values())
    net_args = ['x' + str(i) for i in xrange(0, network_max_index + 1)]
    formula = compile.parse1(
        '{}({}) :- neutron:networks({})'.format(
        tablename,
        'x' + str(network_id_index),
        ",".join(net_args)))
    return formula
def create_network_group(tablename, full_neutron_tablename=None):
    if full_neutron_tablename is None:
        full_neutron_tablename = 'neutron:networks'
    network_key_to_index = NeutronDriver.network_key_position_map()
    network_id_index = network_key_to_index['id']
    network_max_index = max(network_key_to_index.values())
    network_args = ['x' + str(i) for i in xrange(0, network_max_index + 1)]
    formula = compile.parse1(
        '{}({}) :- {}({})'.format(
        tablename,
        'x' + str(network_id_index),
        full_neutron_tablename,
        ",".join(network_args)))
    return formula
def create_network_group(tablename, full_neutron_tablename=None):
    driver = neutron_driver.NeutronDriver(
        args=helper.datasource_openstack_args())
    if full_neutron_tablename is None:
        full_neutron_tablename = 'neutron:networks'
    network_key_to_index = driver.get_column_map(
        neutron_driver.NeutronDriver.NETWORKS)
    network_id_index = network_key_to_index['id']
    network_max_index = max(network_key_to_index.values())
    network_args = ['x' + str(i) for i in xrange(0, network_max_index + 1)]
    formula = compile.parse1('{}({}) :- {}({})'.format(
        tablename, 'x' + str(network_id_index), full_neutron_tablename,
        ",".join(network_args)))
    return formula
Exemple #24
0
def create_networkXnetwork_group(tablename):
    network_key_to_index = NeutronDriver.get_column_map(
        NeutronDriver.NETWORKS)
    network_id_index = network_key_to_index['id']
    network_max_index = max(network_key_to_index.values())
    net1_args = ['x' + str(i) for i in xrange(0, network_max_index + 1)]
    net2_args = ['y' + str(i) for i in xrange(0, network_max_index + 1)]
    formula = compile.parse1(
        '{}({},{}) :- neutron:networks({}), neutron2:networks({})'.format(
        tablename,
        'x' + str(network_id_index),
        'y' + str(network_id_index),
        ",".join(net1_args),
        ",".join(net2_args)))
    return formula
Exemple #25
0
 def test_policy_subscriptions(self):
     """Test that policy engine subscriptions adjust to policy changes."""
     engine = self.engine
     api = self.api
     cage = self.cage
     # Send formula
     helper.pause()
     formula = compile.parse1("p(y) :- neutron:networks(y)")
     LOG.debug("Sending formula: {}".format(str(formula)))
     api['rule'].publish('policy-update', [runtime.Event(formula)])
     helper.pause()  # give time for messages/creation of services
     # check we have the proper subscriptions
     self.assertTrue('neutron' in cage.services)
     neutron = cage.service_object('neutron')
     self.check_subscriptions(engine, [('neutron', 'networks')])
     self.check_subscribers(neutron, [(engine.name, 'networks')])
def create_networkXnetwork_group(tablename):
    """Return rule of the form:

    TABLENAME(x,y) :- neutron:network(...,x,...),neutron:network(...,y,...)
    """
    driver = neutron_driver.NeutronDriver(
        args=helper.datasource_openstack_args())
    network_key_to_index = driver.get_column_map(
        neutron_driver.NeutronDriver.NETWORKS)
    network_id_index = network_key_to_index['id']
    network_max_index = max(network_key_to_index.values())
    net1_args = ['x' + str(i) for i in xrange(0, network_max_index + 1)]
    net2_args = ['y' + str(i) for i in xrange(0, network_max_index + 1)]
    formula = compile.parse1(
        '{}({},{}) :- neutron:networks({}), neutron2:networks({})'.format(
            tablename, 'x' + str(network_id_index),
            'y' + str(network_id_index), ",".join(net1_args),
            ",".join(net2_args)))
    return formula
Exemple #27
0
    def delete_item(self, id_, context=None):
        """Remove item from model.

        Args:
            id_: The ID of the item to be removed
            context: Key-values providing frame of reference of request

        Returns:
             The removed item.

        Raises:
            KeyError: Item with specified id_ not present.
        """
        item = self.get_item(id_, context)
        if item is None:
            raise KeyError('ID %s does not exist', id_)
        rule = compile.parse1(item['rule'])
        self.change_rule(rule, context, insert=False)
        return item
Exemple #28
0
 def test_policy_data(self):
     """Test policy properly inserts data and processes it normally."""
     cage = congress.dse.d6cage.d6Cage()
     cage.loadModule("TestDriver",
                     helper.data_module_path("test_driver.py"))
     cage.loadModule("TestPolicy", helper.policy_module_path())
     cage.createservice(name="data", moduleName="TestDriver",
                        args=helper.datasource_openstack_args())
     cage.createservice(name="policy", moduleName="TestPolicy",
                        args={'d6cage': cage, 'rootdir': ''})
     data = cage.services['data']['object']
     policy = cage.services['policy']['object']
     # turn off module-schema syntax checking
     policy.set_schema('data', compile.Schema({'p': (1,)}))
     policy.subscribe('data', 'p', callback=policy.receive_data)
     formula = compile.parse1('p(1)')
     # sending a single Insert.  (Default for Event is Insert.)
     data.publish('p', [runtime.Event(formula)])
     helper.retry_check_db_equal(policy, 'data:p(x)', 'data:p(1)')
Exemple #29
0
 def test_policy_data(self):
     """Test policy properly inserts data and processes it normally."""
     cage = congress.dse.d6cage.d6Cage()
     # so that we exit once test finishes; all other threads are forced
     #    to be daemons
     cage.daemon = True
     cage.start()
     cage.loadModule("TestDriver",
                     helper.data_module_path("test_driver.py"))
     cage.loadModule("TestPolicy", helper.policy_module_path())
     cage.createservice(name="data", moduleName="TestDriver")
     cage.createservice(name="policy", moduleName="TestPolicy")
     data = cage.services['data']['object']
     policy = cage.services['policy']['object']
     policy.subscribe('data', 'p', callback=policy.receive_data)
     formula = compile.parse1('p(1)')
     # sending a single Insert.  (Default for Event is Insert.)
     data.publish('p', [runtime.Event(formula)])
     helper.pause()  # give other threads chance to run
     e = helper.db_equal(policy.select('data:p(x)'), 'data:p(1)')
     self.assertTrue(e, 'Single insert')
Exemple #30
0
    def delete_item(self, id_, params, context=None):
        """Remove item from model.

        Args:
            id_: The ID of the item to be removed
            params: A dict-like object containing parameters
                    from the request query string and body.
            context: Key-values providing frame of reference of request

        Returns:
             The removed item.

        Raises:
            KeyError: Item with specified id_ not present.
        """
        item = self.get_item(id_, params, context)
        if item is None:
            raise KeyError('ID %s does not exist', id_)
        rule = compile.parse1(item['rule'])
        self.change_rule(rule, context, insert=False)
        db_policy_rules.delete_policy_rule(id_)
        return item
    def benchmark_datasource_to_policy_update(self, size):
        """Benchmark small datsource update to policy propagation.

        Time the propagation of a datasource update from datasource.poll() to
        completion of a simple policy update.
        """
        LOG.info("%s:: benchmarking datasource update of %d rows", size)
        self.datasource.datarows = size
        table_name = self.table_name

        # dummy policy only intended to produce a subscriber for the table
        key_to_index = self.datasource.get_column_map(table_name)
        id_index = 'x%d' % key_to_index.items()[0][1]
        max_index = max(key_to_index.values())
        args = ['x%d' % i for i in xrange(max_index + 1)]
        formula = compile.parse1('p(%s) :- benchmark:%s(%s)' % (id_index,
                                 table_name, ','.join(args)))

        # publish the formula and verify we see a subscription
        LOG.debug('%s:: sending formula: %s', self.__class__.__name__, formula)
        self.api['rule'].publish('policy-update', [runtime.Event(formula)])
        helper.retry_check_subscriptions(
            self.engine, [('benchmark', table_name)])
        helper.retry_check_subscribers(
            self.datasource, [(self.engine.name, table_name)])

        # intercept inbox.task_done() so we know when it's finished. Sadly,
        # eventlet doesn't have a condition-like object.
        fake_condition = eventlet.Queue()
        fake_notify = functools.partial(fake_condition.put_nowait, True)
        self.mox.StubOutWithMock(self.engine.inbox, "task_done")
        self.engine.inbox.task_done().WithSideEffects(fake_notify)
        self.mox.ReplayAll()

        LOG.info("%s:: polling datasource", self.__class__.__name__)
        self.datasource.poll()
        fake_condition.get(timeout=30)
        self.mox.VerifyAll()
Exemple #32
0
 def parse1(self, string):
     return compile.parse1(string, theories=self.theory)
Exemple #33
0
    def get_items(self, params, context=None):
        """Get items in model.

        Args:
            params: A dict-like object containing parameters
                    from the request query string and body.
            context: Key-values providing frame of reference of request

        Returns: A dict containing at least a 'results' key whose value is
                 a list of items in the model.  Additional keys set in the
                 dict will also be rendered for the user.
        """
        LOG.info("get_items(context=%s)", context)
        gen_trace = False
        trace = "Not available"
        if 'trace' in params and params['trace'].lower() == 'true':
            gen_trace = True

        # table defined by data-source
        if 'ds_id' in context:
            service_name = context['ds_id']
            service_obj = self.engine.d6cage.service_object(service_name)
            if service_obj is None:
                LOG.info("Unknown data-source name %s", service_name)
                return {"results": []}
            tablename = context['table_id']
            if tablename not in service_obj.state:
                LOG.info("Unknown tablename %s for datasource %s",
                         service_name, tablename)
                return {"results": []}
            results = []
            for tup in service_obj.state[tablename]:
                d = {}
                d['data'] = tup
                results.append(d)

        # table defined by policy
        elif 'policy_id' in context:
            policy_name = context['policy_id']
            if policy_name not in self.engine.theory:
                LOG.info("Unknown policy name %s", policy_name)
                return {"results": []}
            tablename = context['table_id']
            if tablename not in self.engine.theory[policy_name].tablenames():
                LOG.info("Unknown tablename %s for policy %s",
                         tablename, policy_name)
                return {"results": []}
            arity = self.engine.theory[policy_name].get_arity(tablename)
            if arity is None:
                LOG.info("Unknown arity for table %s for policy %s",
                         tablename, policy_name)
                return {"results": []}
            args = ["x" + str(i) for i in xrange(0, arity)]
            query = compile.parse1(tablename + "(" + ",".join(args) + ")")
            # LOG.debug("query: %s", query)
            result = self.engine.select(query, target=policy_name,
                                        trace=gen_trace)
            if gen_trace:
                literals = result[0]
                trace = result[1]
            else:
                literals = result
            # should NOT need to convert to set -- see bug 1344466
            literals = frozenset(literals)
            # LOG.info("results: %s", '\n'.join(str(x) for x in literals))
            results = []
            for lit in literals:
                d = {}
                d['data'] = [arg.name for arg in lit.arguments]
                results.append(d)

        # unknown
        else:
            LOG.info("Unknown source for row data %s", context)
            results = {"results": []}
        if gen_trace:
            return {"results": results, "trace": trace}
        return {"results": results}
Exemple #34
0
def str2form(formula_string, theories=None):
    return compile.parse1(formula_string, theories=theories)
Exemple #35
0
def str2form(formula_string):
    return compile.parse1(formula_string)
Exemple #36
0
def str2form(formula_string, module_schemas=None):
    return compile.parse1(formula_string, module_schemas=module_schemas)
Exemple #37
0
def str2form(formula_string):
    return compile.parse1(formula_string)
Exemple #38
0
 def check_err(code_string, emsg, msg, f=compile.rule_errors):
     rule = compile.parse1(code_string)
     errs = f(rule, modules)
     self.assertTrue(any(emsg in str(err) for err in errs),
             msg + ":: Failed to find error message '" + emsg +
             "' in: " + ";".join(str(e) for e in errs))
    def test_rule_dependency_graph(self):
        g = compile.RuleDependencyGraph()

        # first insertion
        g.formula_insert(compile.parse1('p(x), q(x) :- r(x), s(x)'))
        self.assertTrue(g.node_in('p'))
        self.assertTrue(g.node_in('q'))
        self.assertTrue(g.node_in('r'))
        self.assertTrue(g.node_in('s'))
        self.assertTrue(g.edge_in('p', 'r', False))
        self.assertTrue(g.edge_in('p', 's', False))
        self.assertTrue(g.edge_in('q', 'r', False))
        self.assertTrue(g.edge_in('q', 's', False))
        self.assertFalse(g.has_cycle())

        # another insertion
        g.formula_insert(compile.parse1('r(x) :- t(x)'))
        self.assertTrue(g.node_in('p'))
        self.assertTrue(g.node_in('q'))
        self.assertTrue(g.node_in('r'))
        self.assertTrue(g.node_in('s'))
        self.assertTrue(g.edge_in('p', 'r', False))
        self.assertTrue(g.edge_in('p', 's', False))
        self.assertTrue(g.edge_in('q', 'r', False))
        self.assertTrue(g.edge_in('q', 's', False))
        self.assertTrue(g.node_in('t'))
        self.assertTrue(g.edge_in('r', 't', False))
        self.assertFalse(g.has_cycle())

        # 3rd insertion, creating a cycle
        g.formula_insert(compile.parse1('t(x) :- p(x)'))
        self.assertTrue(g.edge_in('t', 'p', False))
        self.assertTrue(g.has_cycle())

        # deletion
        g.formula_delete(compile.parse1('p(x), q(x) :- r(x), s(x)'))
        self.assertTrue(g.node_in('p'))
        self.assertTrue(g.node_in('r'))
        self.assertTrue(g.node_in('t'))
        self.assertTrue(g.edge_in('r', 't', False))
        self.assertTrue(g.edge_in('t', 'p', False))
        self.assertFalse(g.has_cycle())

        # double-insertion
        g.formula_insert(compile.parse1('p(x) :- q(x), r(x)'))
        g.formula_insert(compile.parse1('p(1) :- r(1)'))
        self.assertTrue(g.has_cycle())

        # deletion -- checking for bag semantics
        g.formula_delete(compile.parse1('p(1) :- r(1)'))
        self.assertTrue(g.has_cycle())
        g.formula_delete(compile.parse1('p(x) :- q(x), r(x)'))
        self.assertFalse(g.has_cycle())

        # update
        g.formula_update([
            compile.Event(compile.parse1('a(x) :- b(x)')),
            compile.Event(compile.parse1('b(x) :- c(x)')),
            compile.Event(compile.parse1('c(x) :- a(x)'))
        ])
        self.assertTrue(g.has_cycle())
        g.formula_update(
            [compile.Event(compile.parse1('c(x) :- a(x)'), insert=False)])
        self.assertFalse(g.has_cycle())
    def test_module_schemas(self):
        """Test that rules are properly checked against module schemas."""

        run = runtime.Runtime()
        run.create_policy('mod1')
        run.create_policy('mod2')
        run.set_schema('mod1',
                       compile.Schema({
                           'p': (1, 2, 3),
                           'q': (1, )
                       }),
                       complete=True)
        run.set_schema('mod2',
                       compile.Schema({
                           'p': (1, ),
                           'q': (1, 2)
                       }),
                       complete=True)

        def check_err(code_string, theory, emsg, msg, f=compile.rule_errors):
            rule = compile.parse1(code_string)
            errs = f(rule, run.theory, theory)
            self.assertTrue(
                any(emsg in str(err) for err in errs),
                msg + ":: Failed to find error message '" + emsg + "' in: " +
                ";".join(str(e) for e in errs))

        # no errors
        rule = compile.parse1('p(x) :- q(x), mod1:p(x, y, z), mod2:q(x, y), '
                              'mod1:q(t), mod2:p(t)')
        errs = compile.rule_errors(rule, run.theory)
        self.assertEqual(len(errs), 0, "Should not have found any errors")

        # unknown table within module
        check_err('p(x) :- q(x), mod1:r(x), r(x)', 'mod3', 'unknown table',
                  'Unknown table for rule')

        # wrong number of arguments
        check_err('p(x) :- q(x), mod1:p(x,y,z,w), r(x)', 'mod3',
                  'only 3 arguments are permitted',
                  'Wrong number of arguments for rule')

        # same tests for an atom

        # no errors
        atom = compile.parse1('p(1, 2, 2)')
        errs = compile.fact_errors(atom, run.theory, 'mod1')
        self.assertEqual(len(errs), 0, "Should not have found any errors")

        # unknown table within module
        check_err('r(1)',
                  'mod1',
                  'unknown table',
                  'Unknown table for atom',
                  f=compile.fact_errors)

        # wrong number of arguments
        check_err('p(1, 2, 3, 4)',
                  'mod1',
                  'only 3 arguments are permitted',
                  'Wrong number of arguments for atom',
                  f=compile.fact_errors)
Exemple #41
0
 def test_discard_nonexistent_rule(self):
     rule1 = compile.parse1('p(x,y) :- q(x), r(y)')
     self.assertFalse(self.ruleset.discard_rule('p', rule1))
     self.assertFalse('p' in self.ruleset)
     self.assertEqual([], self.ruleset.keys())