Example #1
0
    def test_add_two_rules_and_get(self):
        id1 = uuidutils.generate_uuid()
        rule1_str = "p(x) :- q(x)"
        id2 = uuidutils.generate_uuid()
        rule2_str = "z(x) :- q(x)"
        policy_name = "classification"
        comment = "None"
        db_policy_rules.add_policy_rule(id=id1,
                                        policy_name=policy_name,
                                        rule=rule1_str,
                                        comment=comment)

        db_policy_rules.add_policy_rule(id=id2,
                                        policy_name=policy_name,
                                        rule=rule2_str,
                                        comment=comment)

        rules = db_policy_rules.get_policy_rules(policy_name)
        self.assertEqual(len(rules), 2)
        self.assertEqual(id1, rules[0].id)
        self.assertEqual(policy_name, rules[0].policy_name)
        self.assertEqual(rule1_str, rules[0].rule)
        self.assertEqual(comment, rules[0].comment)
        self.assertEqual(id2, rules[1].id)
        self.assertEqual(policy_name, rules[1].policy_name)
        self.assertEqual(rule2_str, rules[1].rule)
        self.assertEqual(comment, rules[1].comment)
        self.assertEqual(len(db_policy_rules.get_policy_rules()), 2)
Example #2
0
    def test_add_two_rules_and_get(self):
        id1 = uuidutils.generate_uuid()
        rule1_str = "p(x) :- q(x)"
        id2 = uuidutils.generate_uuid()
        rule2_str = "z(x) :- q(x)"
        policy_name = "classification"
        comment = "None"
        db_policy_rules.add_policy_rule(id=id1,
                                        policy_name=policy_name,
                                        rule=rule1_str,
                                        comment=comment)

        db_policy_rules.add_policy_rule(id=id2,
                                        policy_name=policy_name,
                                        rule=rule2_str,
                                        comment=comment)

        rules = db_policy_rules.get_policy_rules(policy_name)
        self.assertEqual(len(rules), 2)
        self.assertEqual(id1, rules[0].id)
        self.assertEqual(policy_name, rules[0].policy_name)
        self.assertEqual(rule1_str, rules[0].rule)
        self.assertEqual(comment, rules[0].comment)
        self.assertEqual(id2, rules[1].id)
        self.assertEqual(policy_name, rules[1].policy_name)
        self.assertEqual(rule2_str, rules[1].rule)
        self.assertEqual(comment, rules[1].comment)
        self.assertEqual(len(db_policy_rules.get_policy_rules()), 2)
Example #3
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.
        """
        policy_name = self.policy_name(context)
        rules = db_policy_rules.get_policy_rules(policy_name)
        results = []
        for rule in rules:
            d = {'rule': rule.rule,
                 'id': rule.id,
                 'comment': rule.comment}
            results.append(d)
        return {'results': results}
Example #4
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.
        """
        policy_name = self.policy_name(context)
        rules = db_policy_rules.get_policy_rules(policy_name)
        results = []
        for rule in rules:
            d = {
                'rule': rule.rule,
                'id': rule.id,
                'comment': rule.comment,
                'name': rule.name
            }
            results.append(d)
        return {'results': results}
Example #5
0
def create(rootdir, statedir, config_override=None):
    """Get Congress up and running when src is installed in rootdir.

    i.e. ROOTDIR=/path/to/congress/congress.
    CONFIG_OVERRIDE is a dictionary of dictionaries with configuration
    values that overrides those provided in CONFIG_FILE.  The top-level
    dictionary has keys for the CONFIG_FILE sections, and the second-level
    dictionaries store values for that section.
    """
    LOG.debug("Starting Congress with rootdir=%s, statedir=%s, "
              "config_override=%s",
              rootdir, statedir, config_override)

    # create message bus
    cage = d6cage.d6Cage()

    # read in datasource configurations

    cage.config = config_override or {}

    # path to congress source dir
    src_path = os.path.join(rootdir, "congress")

    # add policy engine
    engine_path = os.path.join(src_path, "policy_engines/agnostic.py")
    LOG.info("main::start() engine_path: %s", engine_path)
    cage.loadModule("PolicyEngine", engine_path)
    cage.createservice(
        name="engine",
        moduleName="PolicyEngine",
        description="Policy Engine (DseRuntime instance)",
        args={'d6cage': cage, 'rootdir': src_path})
    engine = cage.service_object('engine')
    if statedir is not None:
        engine.load_dir(statedir)
    engine.initialize_table_subscriptions()
    engine.debug_mode()  # should take this out for production

    # add policy api
    api_path = os.path.join(src_path, "api/policy_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-policy", api_path)
    cage.createservice(
        name="api-policy",
        moduleName="API-policy",
        description="API-policy DSE instance",
        args={'policy_engine': engine})

    # add rule api
    api_path = os.path.join(src_path, "api/rule_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-rule", api_path)
    cage.createservice(
        name="api-rule",
        moduleName="API-rule",
        description="API-rule DSE instance",
        args={'policy_engine': engine})

    # add table api
    api_path = os.path.join(src_path, "api/table_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-table", api_path)
    cage.createservice(
        name="api-table",
        moduleName="API-table",
        description="API-table DSE instance",
        args={'policy_engine': engine})

    # add row api
    api_path = os.path.join(src_path, "api/row_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-row", api_path)
    cage.createservice(
        name="api-row",
        moduleName="API-row",
        description="API-row DSE instance",
        args={'policy_engine': engine})

    # add status api
    api_path = os.path.join(src_path, "api/status_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-status", api_path)
    cage.createservice(
        name="api-status",
        moduleName="API-status",
        description="API-status DSE instance",
        args={'policy_engine': engine})

    # add schema api
    api_path = os.path.join(src_path, "api/schema_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-schema", api_path)
    cage.createservice(
        name="api-schema",
        moduleName="API-schema",
        description="API-schema DSE instance",
        args={'policy_engine': engine})

    # add datasource/config api
    api_path = os.path.join(src_path, "api/datasource_config_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-config", api_path)
    cage.createservice(
        name="api-config",
        moduleName="API-config",
        description="API-config DSE instance",
        args={'policy_engine': engine})

    # add path for system/datasource-drivers
    api_path = os.path.join(src_path, "api/system/driver_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-system", api_path)
    cage.createservice(
        name="api-system",
        moduleName="API-system",
        description="API-system DSE instance",
        args={'policy_engine': engine})

    # Load policies from database
    for policy in db_policy_rules.get_policies():
        engine.create_policy(
            policy.name, abbr=policy.abbreviation, kind=policy.kind)

    # if this is the first time we are running Congress, need
    #   to create the default theories (which cannot be deleted)
    api_policy = cage.service_object('api-policy')

    engine.DEFAULT_THEORY = 'classification'
    engine.builtin_policy_names.add(engine.DEFAULT_THEORY)
    try:
        api_policy.add_item({'name': engine.DEFAULT_THEORY,
                             'description': 'default policy'}, {})
    except KeyError:
        pass

    engine.ACTION_THEORY = 'action'
    engine.builtin_policy_names.add(engine.ACTION_THEORY)
    try:
        api_policy.add_item({'kind': ACTION_POLICY_TYPE,
                             'name': engine.ACTION_THEORY,
                             'description': 'default action policy'},
                            {})
    except KeyError:
        pass

    # have policy-engine subscribe to api calls
    # TODO(thinrichs): either have API publish everything to DSE bus and
    #   have policy engine subscribe to all those messages
    #   OR have API interact with individual components directly
    #   and change all tests so that the policy engine does not need to be
    #   subscribed to 'policy-update'
    engine.subscribe('api-rule', 'policy-update',
                     callback=engine.receive_policy_update)

    # spin up all the configured services, if we have configured them

    datasource_mgr = datasource_manager.DataSourceManager
    drivers = datasource_mgr.get_datasources()
    # Setup cage.config as it previously done when it was loaded
    # from disk. FIXME(arosen) later!
    for driver in drivers:
        if not driver['enabled']:
            LOG.info("module %s not enabled, skip loading", driver['name'])
            continue
        driver_info = datasource_mgr.get_driver_info(driver['driver'])
        engine.create_policy(driver['name'])
        try:
            cage.createservice(name=driver['name'],
                               moduleName=driver_info['module'],
                               args=driver['config'],
                               module_driver=True,
                               type_='datasource_driver',
                               id_=driver['id'])
        except d6cage.DataServiceError:
            # FIXME(arosen): If createservice raises congress-server
            # dies here. So we catch this exception so the server does
            # not die. We need to refactor the dse code so it just
            # keeps retrying the driver gracefully...
            continue
        service = cage.service_object(driver['name'])
        engine.set_schema(driver['name'], service.get_schema())

    # Insert rules.  Needs to be done after datasources are loaded
    #  so that we can compile away column references at read time.
    #  If datasources loaded after this, we don't have schemas.
    rules = db_policy_rules.get_policy_rules()
    for rule in rules:
        parsed_rule = engine.parse1(rule.rule)
        cage.service_object('api-rule').change_rule(
            parsed_rule,
            {'policy_id': rule.policy_name})

    # Start datasource synchronizer after explicitly starting the
    # datasources, because the explicit call to create a datasource
    # will crash if the synchronizer creates the datasource first.
    synchronizer_path = os.path.join(src_path, "synchronizer.py")
    LOG.info("main::start() synchronizer: %s", synchronizer_path)
    cage.loadModule("Synchronizer", synchronizer_path)
    cage.createservice(
        name="synchronizer",
        moduleName="Synchronizer",
        description="DB synchronizer instance",
        args={'poll_time': cfg.CONF.datasource_sync_period})
    synchronizer = cage.service_object('synchronizer')

    # add datasource api
    api_path = os.path.join(src_path, "api/datasource_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-datasource", api_path)
    cage.createservice(
        name="api-datasource",
        moduleName="API-datasource",
        description="API-datasource DSE instance",
        args={'policy_engine': engine, 'synchronizer': synchronizer})

    return cage
    def synchronize_rules_nonlocking(self, db_session=None):
        LOG.debug("Synchronizing rules on node %s", self.node.node_id)
        try:
            # Read rules from DB.
            configured_rules = []
            configured_facts = []
            for r in db_policy_rules.get_policy_rules(session=db_session):
                if ':-' in r.rule:  # if rule has body
                    configured_rules.append({'rule': r.rule,
                                             'id': r.id,
                                             'comment': r.comment,
                                             'name': r.name,
                                             'policy_name': r.policy_name})
                else:  # head-only rule, ie., fact
                    configured_facts.append(
                        {'rule': self.engine.parse1(r.rule).pretty_str(),
                         # note:parse to remove effect of extraneous formatting
                         'policy_name': r.policy_name})

            # Read rules from engine
            policies = {n: self.engine.policy_object(n) for n in
                        self.engine.policy_names()}
            active_policy_rules = []
            active_policy_facts = []
            for policy_name, policy in policies.items():
                if policy.kind != base.DATASOURCE_POLICY_TYPE:
                    for active_rule in policy.content():
                        # FIXME: This assumes r.original_str is None iff
                        # r is a head-only rule (fact). This works in
                        # non-recursive policy but not in recursive policies
                        if active_rule.original_str is None:
                            active_policy_facts.append(
                                {'rule': str(active_rule.head),
                                 'policy_name': policy_name})
                        else:
                            active_policy_rules.append(
                                {'rule': active_rule.original_str,
                                 'id': active_rule.id,
                                 'comment': active_rule.comment,
                                 'name': active_rule.name,
                                 'policy_name': policy_name})

            # ALEX: the Rule object does not have fields like the rule-string
            # or id or comment.  We can add those fields to the Rule object,
            # as long as we don't add them to the Fact because there are many
            # fact instances.  If a user tries to create a lot of Rules, they
            # are probably doing something wrong and should use a datasource
            # driver instead.

            changes = []

            # add configured rules
            for r in configured_rules:
                if r not in active_policy_rules:
                    LOG.debug("adding rule %s", str(r))
                    parsed_rule = self.engine.parse1(r['rule'])
                    parsed_rule.set_id(r['id'])
                    parsed_rule.set_name(r['name'])
                    parsed_rule.set_comment(r['comment'])
                    parsed_rule.set_original_str(r['rule'])

                    event = compile.Event(formula=parsed_rule,
                                          insert=True,
                                          target=r['policy_name'])
                    changes.append(event)

            # add configured facts
            for r in configured_facts:
                if r not in active_policy_facts:
                    LOG.debug("adding rule %s", str(r))
                    parsed_rule = self.engine.parse1(r['rule'])
                    event = compile.Event(formula=parsed_rule,
                                          insert=True,
                                          target=r['policy_name'])
                    changes.append(event)

            # remove active rules not configured
            for r in active_policy_rules:
                if r not in configured_rules:
                    LOG.debug("removing rule %s", str(r))
                    parsed_rule = self.engine.parse1(r['rule'])
                    parsed_rule.set_id(r['id'])
                    parsed_rule.set_name(r['name'])
                    parsed_rule.set_comment(r['comment'])
                    parsed_rule.set_original_str(r['rule'])

                    event = compile.Event(formula=parsed_rule,
                                          insert=False,
                                          target=r['policy_name'])
                    changes.append(event)

            # remove active facts not configured
            for r in active_policy_facts:
                if r not in configured_facts:
                    LOG.debug("removing rule %s", str(r))
                    parsed_rule = self.engine.parse1(r['rule'])
                    event = compile.Event(formula=parsed_rule,
                                          insert=False,
                                          target=r['policy_name'])
                    changes.append(event)

            permitted, changes = self.engine.process_policy_update(changes)
            LOG.info("synchronize_rules, permitted %d, made %d changes on "
                     "node %s", permitted, len(changes), self.node.node_id)
        except Exception:
            LOG.exception("synchronizing rules failed")
Example #7
0
def create(rootdir, statedir, config_file, config_override=None):
    """Get Congress up and running when src is installed in rootdir,
    i.e. ROOTDIR=/path/to/congress/congress.
    CONFIG_OVERRIDE is a dictionary of dictionaries with configuration
    values that overrides those provided in CONFIG_FILE.  The top-level
    dictionary has keys for the CONFIG_FILE sections, and the second-level
    dictionaries store values for that section.
    """
    LOG.debug("Starting Congress with rootdir=%s, statedir=%s, "
              "datasource_config=%s, config_override=%s",
              rootdir, statedir, config_file, config_override)

    # create message bus
    cage = d6cage.d6Cage()
    cage.system_service_names.add(cage.name)

    # read in datasource configurations
    cage.config = initialize_config(config_file, config_override)

    # path to congress source dir
    src_path = os.path.join(rootdir, "congress")

    # add policy engine
    engine_path = os.path.join(src_path, "policy/dsepolicy.py")
    LOG.info("main::start() engine_path: %s", engine_path)
    cage.loadModule("PolicyEngine", engine_path)
    cage.createservice(
        name="engine",
        moduleName="PolicyEngine",
        description="Policy Engine (DseRuntime instance)",
        args={'d6cage': cage, 'rootdir': src_path})
    engine = cage.service_object('engine')
    if statedir is not None:
        engine.load_dir(statedir)
    engine.initialize_table_subscriptions()
    cage.system_service_names.add(engine.name)
    engine.debug_mode()  # should take this out for production

    # add policy api
    # TODO(thinrichs): change to real API path.
    api_path = os.path.join(src_path, "api/policy_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-policy", api_path)
    cage.createservice(
        name="api-policy",
        moduleName="API-policy",
        description="API-policy DSE instance",
        args={'policy_engine': engine})
    cage.system_service_names.add('api-policy')

    # add rule api
    api_path = os.path.join(src_path, "api/rule_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-rule", api_path)
    cage.createservice(
        name="api-rule",
        moduleName="API-rule",
        description="API-rule DSE instance",
        args={'policy_engine': engine})
    cage.system_service_names.add('api-rule')

    # add table api
    api_path = os.path.join(src_path, "api/table_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-table", api_path)
    cage.createservice(
        name="api-table",
        moduleName="API-table",
        description="API-table DSE instance",
        args={'policy_engine': engine})
    cage.system_service_names.add('api-table')

    # add row api
    api_path = os.path.join(src_path, "api/row_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-row", api_path)
    cage.createservice(
        name="api-row",
        moduleName="API-row",
        description="API-row DSE instance",
        args={'policy_engine': engine})
    cage.system_service_names.add('api-row')

    # add datasource api
    api_path = os.path.join(src_path, "api/datasource_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-datasource", api_path)
    cage.createservice(
        name="api-datasource",
        moduleName="API-datasource",
        description="API-datasource DSE instance",
        args={'policy_engine': engine})
    cage.system_service_names.add('api-datasource')

    # add status api
    api_path = os.path.join(src_path, "api/status_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-status", api_path)
    cage.createservice(
        name="api-status",
        moduleName="API-status",
        description="API-status DSE instance",
        args={'policy_engine': engine})
    cage.system_service_names.add('api-status')

    # add schema api
    api_path = os.path.join(src_path, "api/schema_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-schema", api_path)
    cage.createservice(
        name="api-schema",
        moduleName="API-schema",
        description="API-schema DSE instance",
        args={'policy_engine': engine})
    cage.system_service_names.add('api-schema')

    # have policy-engine subscribe to api calls
    # TODO(thinrichs): either have API publish everything to DSE bus and
    #   have policy engine subscribe to all those messages
    #   OR have API interact with individual components directly
    #   and change all tests so that the policy engine does not need to be
    #   subscribed to 'policy-update'
    engine.subscribe('api-rule', 'policy-update',
                     callback=engine.receive_policy_update)

    # spin up all the configured services, if we have configured them
    if cage.config:
        for name in cage.config:
            if 'module' in cage.config[name]:
                load_data_service(name, cage.config[name], cage, src_path)
                # inform policy engine about schema
                service = cage.service_object(name)
                engine.set_schema(name, service.get_schema())

        # populate rule api data, needs to be done after models are loaded.
        # FIXME(arosen): refactor how we're loading data and api.
        rules = db_policy_rules.get_policy_rules()
        for rule in rules:
            parsed_rule = compile.parse(rule.rule)[0]
            cage.services['api-rule']['object'].change_rule(
                parsed_rule,
                {'policy_id': rule.policy_name})

        return cage
Example #8
0
def create(rootdir, statedir, config_override=None):
    """Get Congress up and running when src is installed in rootdir.

    i.e. ROOTDIR=/path/to/congress/congress.
    CONFIG_OVERRIDE is a dictionary of dictionaries with configuration
    values that overrides those provided in CONFIG_FILE.  The top-level
    dictionary has keys for the CONFIG_FILE sections, and the second-level
    dictionaries store values for that section.
    """
    LOG.debug(
        "Starting Congress with rootdir=%s, statedir=%s, "
        "config_override=%s", rootdir, statedir, config_override)

    # create message bus
    cage = d6cage.d6Cage()

    # read in datasource configurations

    cage.config = config_override or {}

    # path to congress source dir
    src_path = os.path.join(rootdir, "congress")

    # add policy engine
    engine_path = os.path.join(src_path, "policy_engines/agnostic.py")
    LOG.info("main::start() engine_path: %s", engine_path)
    cage.loadModule("PolicyEngine", engine_path)
    cage.createservice(name="engine",
                       moduleName="PolicyEngine",
                       description="Policy Engine (DseRuntime instance)",
                       args={
                           'd6cage': cage,
                           'rootdir': src_path
                       })
    engine = cage.service_object('engine')
    if statedir is not None:
        engine.load_dir(statedir)
    engine.initialize_table_subscriptions()
    engine.debug_mode()  # should take this out for production

    # add policy api
    api_path = os.path.join(src_path, "api/policy_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-policy", api_path)
    cage.createservice(name="api-policy",
                       moduleName="API-policy",
                       description="API-policy DSE instance",
                       args={'policy_engine': engine})

    # add rule api
    api_path = os.path.join(src_path, "api/rule_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-rule", api_path)
    cage.createservice(name="api-rule",
                       moduleName="API-rule",
                       description="API-rule DSE instance",
                       args={'policy_engine': engine})

    # add table api
    api_path = os.path.join(src_path, "api/table_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-table", api_path)
    cage.createservice(name="api-table",
                       moduleName="API-table",
                       description="API-table DSE instance",
                       args={'policy_engine': engine})

    # add row api
    api_path = os.path.join(src_path, "api/row_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-row", api_path)
    cage.createservice(name="api-row",
                       moduleName="API-row",
                       description="API-row DSE instance",
                       args={'policy_engine': engine})

    # add status api
    api_path = os.path.join(src_path, "api/status_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-status", api_path)
    cage.createservice(name="api-status",
                       moduleName="API-status",
                       description="API-status DSE instance",
                       args={'policy_engine': engine})

    # add schema api
    api_path = os.path.join(src_path, "api/schema_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-schema", api_path)
    cage.createservice(name="api-schema",
                       moduleName="API-schema",
                       description="API-schema DSE instance",
                       args={'policy_engine': engine})

    # add datasource/config api
    api_path = os.path.join(src_path, "api/datasource_config_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-config", api_path)
    cage.createservice(name="api-config",
                       moduleName="API-config",
                       description="API-config DSE instance",
                       args={'policy_engine': engine})

    # add path for system/datasource-drivers
    api_path = os.path.join(src_path, "api/system/driver_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-system", api_path)
    cage.createservice(name="api-system",
                       moduleName="API-system",
                       description="API-system DSE instance",
                       args={'policy_engine': engine})

    # Load policies from database
    for policy in db_policy_rules.get_policies():
        engine.create_policy(policy.name,
                             abbr=policy.abbreviation,
                             kind=policy.kind)

    # if this is the first time we are running Congress, need
    #   to create the default theories (which cannot be deleted)
    api_policy = cage.service_object('api-policy')

    engine.DEFAULT_THEORY = 'classification'
    engine.builtin_policy_names.add(engine.DEFAULT_THEORY)
    try:
        api_policy.add_item(
            {
                'name': engine.DEFAULT_THEORY,
                'description': 'default policy'
            }, {})
    except KeyError:
        pass

    engine.ACTION_THEORY = 'action'
    engine.builtin_policy_names.add(engine.ACTION_THEORY)
    try:
        api_policy.add_item(
            {
                'kind': ACTION_POLICY_TYPE,
                'name': engine.ACTION_THEORY,
                'description': 'default action policy'
            }, {})
    except KeyError:
        pass

    # have policy-engine subscribe to api calls
    # TODO(thinrichs): either have API publish everything to DSE bus and
    #   have policy engine subscribe to all those messages
    #   OR have API interact with individual components directly
    #   and change all tests so that the policy engine does not need to be
    #   subscribed to 'policy-update'
    engine.subscribe('api-rule',
                     'policy-update',
                     callback=engine.receive_policy_update)

    # spin up all the configured services, if we have configured them

    datasource_mgr = datasource_manager.DataSourceManager
    drivers = datasource_mgr.get_datasources()
    # Setup cage.config as it previously done when it was loaded
    # from disk. FIXME(arosen) later!
    for driver in drivers:
        if not driver['enabled']:
            LOG.info("module %s not enabled, skip loading", driver['name'])
            continue
        driver_info = datasource_mgr.get_driver_info(driver['driver'])
        engine.create_policy(driver['name'])
        try:
            cage.createservice(name=driver['name'],
                               moduleName=driver_info['module'],
                               args=driver['config'],
                               module_driver=True,
                               type_='datasource_driver',
                               id_=driver['id'])
        except d6cage.DataServiceError:
            # FIXME(arosen): If createservice raises congress-server
            # dies here. So we catch this exception so the server does
            # not die. We need to refactor the dse code so it just
            # keeps retrying the driver gracefully...
            continue
        service = cage.service_object(driver['name'])
        engine.set_schema(driver['name'], service.get_schema())

    # Insert rules.  Needs to be done after datasources are loaded
    #  so that we can compile away column references at read time.
    #  If datasources loaded after this, we don't have schemas.
    rules = db_policy_rules.get_policy_rules()
    for rule in rules:
        parsed_rule = engine.parse1(rule.rule)
        cage.service_object('api-rule').change_rule(
            parsed_rule, {'policy_id': rule.policy_name})

    # Start datasource synchronizer after explicitly starting the
    # datasources, because the explicit call to create a datasource
    # will crash if the synchronizer creates the datasource first.
    synchronizer_path = os.path.join(src_path, "synchronizer.py")
    LOG.info("main::start() synchronizer: %s", synchronizer_path)
    cage.loadModule("Synchronizer", synchronizer_path)
    cage.createservice(name="synchronizer",
                       moduleName="Synchronizer",
                       description="DB synchronizer instance",
                       args={'poll_time': cfg.CONF.datasource_sync_period})
    synchronizer = cage.service_object('synchronizer')

    # add datasource api
    api_path = os.path.join(src_path, "api/datasource_model.py")
    LOG.info("main::start() api_path: %s", api_path)
    cage.loadModule("API-datasource", api_path)
    cage.createservice(name="api-datasource",
                       moduleName="API-datasource",
                       description="API-datasource DSE instance",
                       args={
                           'policy_engine': engine,
                           'synchronizer': synchronizer
                       })

    return cage
Example #9
0
    def synchronize_rules(self):
        LOG.debug("Synchronizing rules")

        # Read rules from DB.
        cage = d6cage.d6Cage()
        configured_rules = [{'rule': r.rule,
                             'id': r.id,
                             'comment': r.comment,
                             'name': r.name,
                             'policy_name': r.policy_name}
                            for r in db_policy_rules.get_policy_rules()]

        # Read rules from engine
        engine = cage.service_object('engine')
        policies = {n: engine.policy_object(n) for n in engine.policy_names()}
        active_policy_rules = []
        for policy_name, policy in policies.items():
            if policy.kind != base.DATASOURCE_POLICY_TYPE:
                for active_rule in policy.content():
                    active_policy_rules.append(
                        {'rule': active_rule.original_str,
                         'id': active_rule.id,
                         'comment': active_rule.comment,
                         'name': active_rule.name,
                         'policy_name': policy_name})

        # ALEX: the Rule object does not have fields like the rule-string or
        # id or comment.  We can add those fields to the Rule object, as long
        # as we don't add them to the Fact because there are many fact
        # instances.  If a user tries to create a lot of Rules, they are
        # probably doing something wrong and should use a datasource driver
        # instead.

        changes = []
        for r in configured_rules:
            if r not in active_policy_rules:
                LOG.debug("adding rule %s", str(r))
                parsed_rule = engine.parse1(r['rule'])
                parsed_rule.set_id(r['id'])
                parsed_rule.set_name(r['name'])
                parsed_rule.set_comment(r['comment'])
                parsed_rule.set_original_str(r['rule'])

                event = compile.Event(formula=parsed_rule,
                                      insert=True,
                                      target=r['policy_name'])
                changes.append(event)

        for r in active_policy_rules:
            if r not in configured_rules:
                LOG.debug("removing rule %s", str(r))
                parsed_rule = engine.parse1(r['rule'])
                parsed_rule.set_id(r['id'])
                parsed_rule.set_name(r['name'])
                parsed_rule.set_comment(r['comment'])
                parsed_rule.set_original_str(r['rule'])

                event = compile.Event(formula=parsed_rule,
                                      insert=False,
                                      target=r['policy_name'])
                changes.append(event)
        permitted, changes = engine.process_policy_update(changes)
        LOG.debug("synchronize_rules, permitted %d, made %d changes",
                  permitted, len(changes))