blob: 9c4a5ef7b1018a9a6f1b36f949784f5325376eb7 [file] [log] [blame]
Adam Tenglerb1ebaca2017-05-04 21:06:08 +00001import io
2import json
3import logging
Benjamin Drung5fe80412018-02-14 23:55:54 +01004import sys
Adam Tenglerb1ebaca2017-05-04 21:06:08 +00005
Petr Michalec073067a2017-10-27 15:37:46 +02006LOG = logging.getLogger(__name__)
Alexey Stupnikove124c3b2017-10-19 19:58:09 +03007
Kirill Bespalov4fe0d082017-06-29 19:02:13 +03008import yaml
Petr Michalec073067a2017-10-27 15:37:46 +02009import yaml.constructor
Kirill Bespalov4fe0d082017-06-29 19:02:13 +030010
Petr Michalec073067a2017-10-27 15:37:46 +020011try:
12 # included in standard lib from Python 2.7
13 from collections import OrderedDict
14except ImportError:
15 # try importing the backported drop-in replacement
16 # it's available on PyPI
17 from ordereddict import OrderedDict
18
19# https://stackoverflow.com/questions/5121931/in-python-how-can-you-load-yaml-mappings-as-ordereddicts
20class OrderedDictYAMLLoader(yaml.Loader):
21 """
22 A YAML loader that loads mappings into ordered dictionaries.
23 """
24
25 def __init__(self, *args, **kwargs):
26 yaml.Loader.__init__(self, *args, **kwargs)
27
28 self.add_constructor(u'tag:yaml.org,2002:map', type(self).construct_yaml_map)
29 self.add_constructor(u'tag:yaml.org,2002:omap', type(self).construct_yaml_map)
30
31 def construct_yaml_map(self, node):
32 data = OrderedDict()
33 yield data
34 value = self.construct_mapping(node)
35 data.update(value)
36
37 def construct_mapping(self, node, deep=False):
38 if isinstance(node, yaml.MappingNode):
39 self.flatten_mapping(node)
40 else:
41 raise yaml.constructor.ConstructorError(None, None,
42 'expected a mapping node, but found %s' % node.id, node.start_mark)
43
44 mapping = OrderedDict()
45 for key_node, value_node in node.value:
46 key = self.construct_object(key_node, deep=deep)
47 try:
48 hash(key)
Benjamin Drung5fe80412018-02-14 23:55:54 +010049 except TypeError as exc:
Petr Michalec073067a2017-10-27 15:37:46 +020050 raise yaml.constructor.ConstructorError('while constructing a mapping',
51 node.start_mark, 'found unacceptable key (%s)' % exc, key_node.start_mark)
52 value = self.construct_object(value_node, deep=deep)
53 mapping[key] = value
54 return mapping
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000055
56
57def __virtual__():
58 return True
59
60
Martin Polreiche98edbd2019-11-25 16:09:24 +010061def rule_list(path, ordered_dict = True, **kwargs):
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000062 try:
63 with io.open(path, 'r') as file_handle:
Martin Polreiche98edbd2019-11-25 16:09:24 +010064 if ordered_dict:
65 rules = yaml.load(file_handle, OrderedDictYAMLLoader) or OrderedDict()
66 else:
67 rules = yaml.safe_load(file_handle) or {}
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000068 except Exception as e:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +030069 msg = "Unable to load policy file %s: %s" % (path, repr(e))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000070 LOG.debug(msg)
71 rules = {'Error': msg}
72 return rules
73
74
75def rule_delete(name, path, **kwargs):
76 ret = {}
77 rules = __salt__['keystone_policy.rule_list'](path, **kwargs)
78 if 'Error' not in rules:
79 if name not in rules:
80 return ret
81 del rules[name]
82 try:
83 with io.open(path, 'w') as file_handle:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +030084 if path.endswith('json'):
85 serialized = json.dumps(rules, indent=4)
86 else:
87 serialized = yaml.safe_dump(rules, indent=4)
Benjamin Drung5fe80412018-02-14 23:55:54 +010088 if sys.version_info[0] >= 3:
89 file_handle.write(serialized)
90 else:
91 file_handle.write(unicode(serialized))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000092 except Exception as e:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +030093 msg = "Unable to save policy file: %s" % repr(e)
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000094 LOG.error(msg)
95 return {'Error': msg}
96 ret = 'Rule {0} deleted'.format(name)
97 return ret
98
99
100def rule_set(name, rule, path, **kwargs):
101 rules = __salt__['keystone_policy.rule_list'](path, **kwargs)
102 if 'Error' not in rules:
103 if name in rules and rules[name] == rule:
104 return {name: 'Rule %s already exists and is in correct state' % name}
105 rules.update({name: rule})
106 try:
107 with io.open(path, 'w') as file_handle:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +0300108 if path.endswith('json'):
109 serialized = json.dumps(rules, indent=4)
110 else:
111 serialized = yaml.safe_dump(rules, indent=4)
Benjamin Drung5fe80412018-02-14 23:55:54 +0100112 if sys.version_info[0] >= 3:
113 file_handle.write(serialized)
114 else:
115 file_handle.write(unicode(serialized))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +0000116 except Exception as e:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +0300117 msg = "Unable to save policy file %s: %s" % (path, repr(e))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +0000118 LOG.error(msg)
119 return {'Error': msg}
120 return rule_get(name, path, **kwargs)
121 return rules
122
123
124def rule_get(name, path, **kwargs):
125 ret = {}
126 rules = __salt__['keystone_policy.rule_list'](path, **kwargs)
127 if 'Error' in rules:
128 ret['Error'] = rules['Error']
129 elif name in rules:
130 ret[name] = rules.get(name)
131
132 return ret
133