blob: f3cf8ee12a42eb57889f75a014a349624fa117c6 [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
61def rule_list(path, **kwargs):
62 try:
63 with io.open(path, 'r') as file_handle:
Petr Michalec073067a2017-10-27 15:37:46 +020064 rules = yaml.load(file_handle, OrderedDictYAMLLoader) or OrderedDict()
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000065 except Exception as e:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +030066 msg = "Unable to load policy file %s: %s" % (path, repr(e))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000067 LOG.debug(msg)
68 rules = {'Error': msg}
69 return rules
70
71
72def rule_delete(name, path, **kwargs):
73 ret = {}
74 rules = __salt__['keystone_policy.rule_list'](path, **kwargs)
75 if 'Error' not in rules:
76 if name not in rules:
77 return ret
78 del rules[name]
79 try:
80 with io.open(path, 'w') as file_handle:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +030081 if path.endswith('json'):
82 serialized = json.dumps(rules, indent=4)
83 else:
84 serialized = yaml.safe_dump(rules, indent=4)
Benjamin Drung5fe80412018-02-14 23:55:54 +010085 if sys.version_info[0] >= 3:
86 file_handle.write(serialized)
87 else:
88 file_handle.write(unicode(serialized))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000089 except Exception as e:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +030090 msg = "Unable to save policy file: %s" % repr(e)
Adam Tenglerb1ebaca2017-05-04 21:06:08 +000091 LOG.error(msg)
92 return {'Error': msg}
93 ret = 'Rule {0} deleted'.format(name)
94 return ret
95
96
97def rule_set(name, rule, path, **kwargs):
98 rules = __salt__['keystone_policy.rule_list'](path, **kwargs)
99 if 'Error' not in rules:
100 if name in rules and rules[name] == rule:
101 return {name: 'Rule %s already exists and is in correct state' % name}
102 rules.update({name: rule})
103 try:
104 with io.open(path, 'w') as file_handle:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +0300105 if path.endswith('json'):
106 serialized = json.dumps(rules, indent=4)
107 else:
108 serialized = yaml.safe_dump(rules, indent=4)
Benjamin Drung5fe80412018-02-14 23:55:54 +0100109 if sys.version_info[0] >= 3:
110 file_handle.write(serialized)
111 else:
112 file_handle.write(unicode(serialized))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +0000113 except Exception as e:
Kirill Bespalov4fe0d082017-06-29 19:02:13 +0300114 msg = "Unable to save policy file %s: %s" % (path, repr(e))
Adam Tenglerb1ebaca2017-05-04 21:06:08 +0000115 LOG.error(msg)
116 return {'Error': msg}
117 return rule_get(name, path, **kwargs)
118 return rules
119
120
121def rule_get(name, path, **kwargs):
122 ret = {}
123 rules = __salt__['keystone_policy.rule_list'](path, **kwargs)
124 if 'Error' in rules:
125 ret['Error'] = rules['Error']
126 elif name in rules:
127 ret[name] = rules.get(name)
128
129 return ret
130