diff options
author | Andrew Laski <andrew@lascii.com> | 2016-05-25 17:18:37 -0400 |
---|---|---|
committer | Andrew Laski <andrew@lascii.com> | 2016-06-08 15:12:53 -0400 |
commit | 85ebe9eb5f230de79bd46ec1feb44c962fa4a2ee (patch) | |
tree | 2e5b0d56f56fceef83eaade4e9919037309a087c /oslo_policy/generator.py | |
parent | 474c120ae6de61c1f46523baa0fef11b5e537cf8 (diff) | |
download | oslo-policy-85ebe9eb5f230de79bd46ec1feb44c962fa4a2ee.tar.gz |
Add helper scripts for generating policy info
This adds two helper scripts that consuming projects can use to get
information that helps deployers.
The oslopolicy-policy-generator script looks at an entry_point for a
configured policy.Enforcer and outputs a yaml formatted policy file for
that configuration. This is a merge of registered rules and configured
rules.
The oslopolicy_list_redundant script looks at an entry_point for a
configured policy.Enforcer and outputs a yaml formatted policy file with
a list of policies where the registered default matches the project
configuration. These are policies that can be removed from the
configuration file(s) without affecting policy.
Change-Id: Ibe4e6c9288768bcc8f532e384524580c57e58275
Implements: bp policy-sample-generation
Diffstat (limited to 'oslo_policy/generator.py')
-rw-r--r-- | oslo_policy/generator.py | 96 |
1 files changed, 94 insertions, 2 deletions
diff --git a/oslo_policy/generator.py b/oslo_policy/generator.py index 2d66b5d..5cbfd6a 100644 --- a/oslo_policy/generator.py +++ b/oslo_policy/generator.py @@ -17,17 +17,29 @@ import textwrap from oslo_config import cfg import stevedore +from oslo_policy import policy + LOG = logging.getLogger(__name__) _generator_opts = [ cfg.StrOpt('output-file', help='Path of the file to write to. Defaults to stdout.'), +] + +_rule_opts = [ cfg.MultiStrOpt('namespace', required=True, help='Option namespace(s) under "oslo.policy.policies" in ' 'which to query for options.'), ] +_enforcer_opts = [ + cfg.StrOpt('namespace', + required=True, + help='Option namespace under "oslo.policy.enforcer" in ' + 'which to look for a policy.Enforcer.'), +] + def _get_policies_dict(namespaces): """Find the options available via the given namespaces. @@ -47,6 +59,23 @@ def _get_policies_dict(namespaces): return opts +def _get_enforcer(namespace): + """Find a policy.Enforcer via an entry point with the given namespace. + + :param namespace: a namespace under oslo.policy.enforcer where the desired + enforcer object can be found. + :returns: a policy.Enforcer object + """ + mgr = stevedore.named.NamedExtensionManager( + 'oslo.policy.enforcer', + names=[namespace], + on_load_failure_callback=on_load_failure_callback, + invoke_on_load=True) + enforcer = mgr[namespace].obj + + return enforcer + + def _format_help_text(description): """Format a comment for a policy based on the description provided. @@ -117,6 +146,51 @@ def _generate_sample(namespaces, output_file=None): output_file.write(section) +def _generate_policy(namespace, output_file=None): + """Generate a policy file showing what will be used. + + This takes all registered policies and merges them with what's defined in + a policy file and outputs the result. That result is the effective policy + that will be honored by policy checks. + + :param output_file: The path of a file to output to. stdout used if None. + """ + enforcer = _get_enforcer(namespace) + # Ensure that files have been parsed + enforcer.load_rules() + + file_rules = [policy.RuleDefault(name, default.check_str) + for name, default in enforcer.file_rules.items()] + registered_rules = [policy.RuleDefault(name, default.check_str) + for name, default in enforcer.registered_rules.items() + if name not in enforcer.file_rules] + policies = {'rules': file_rules + registered_rules} + + output_file = (open(output_file, 'w') if output_file + else sys.stdout) + + for section in _sort_and_format_by_section(policies, include_help=False): + output_file.write(section) + + +def _list_redundant(namespace): + """Generate a list of configured policies which match defaults. + + This checks all policies loaded from policy files and checks to see if they + match registered policies. If so then it is redundant to have them defined + in a policy file and operators should consider removing them. + """ + enforcer = _get_enforcer(namespace) + # Ensure that files have been parsed + enforcer.load_rules() + + for name, file_rule in enforcer.file_rules.items(): + reg_rule = enforcer.registered_rules.get(name, None) + if reg_rule: + if file_rule == reg_rule: + print(reg_rule) + + def on_load_failure_callback(*args, **kwargs): raise @@ -124,7 +198,25 @@ def on_load_failure_callback(*args, **kwargs): def generate_sample(args=None): logging.basicConfig(level=logging.WARN) conf = cfg.ConfigOpts() - conf.register_cli_opts(_generator_opts) - conf.register_opts(_generator_opts) + conf.register_cli_opts(_generator_opts + _rule_opts) + conf.register_opts(_generator_opts + _rule_opts) conf(args) _generate_sample(conf.namespace, conf.output_file) + + +def generate_policy(args=None): + logging.basicConfig(level=logging.WARN) + conf = cfg.ConfigOpts() + conf.register_cli_opts(_generator_opts + _enforcer_opts) + conf.register_opts(_generator_opts + _enforcer_opts) + conf(args) + _generate_policy(conf.namespace, conf.output_file) + + +def list_redundant(args=None): + logging.basicConfig(level=logging.WARN) + conf = cfg.ConfigOpts() + conf.register_cli_opts(_enforcer_opts) + conf.register_opts(_enforcer_opts) + conf(args) + _list_redundant(conf.namespace) |