-
Notifications
You must be signed in to change notification settings - Fork 43
/
postconf.py
120 lines (96 loc) · 3.85 KB
/
postconf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""Classes that wrap the postconf command line utility.
"""
import collections
from certbot import errors
from certbot_postfix import util
class ConfigMain(util.PostfixUtilBase):
"""A parser for Postfix's main.cf file."""
_modifiers = None
_db = None
_updated = {}
"""An iterable containing additional CLI flags for postconf."""
def __init__(self, executable, config_dir=None):
util.PostfixUtilBase.__init__(self, executable, config_dir)
self._db = {}
self._read_from_conf()
def _read_from_conf(self):
"""Reads initial parameter state from main.cf
"""
out = self._get_output()
for name, value in _parse_main_output(out):
if not value:
value = ""
self._db[name] = value
def get_default(self, name):
"""Retrieves default value of parameter |name| from postfix parameters.
:param str name: The name of the parameter to fetch.
:rtype str: The default value of parameter |name|.
"""
out = self._get_output(['-d', name])
_, value = next(_parse_main_output(out), (None, None))
return value
def get(self, name):
"""Retrieves working value of parameter |name| from postfix parameters.
:param str name: The name of the parameter to fetch.
:rtype str: The value of parameter |name|.
"""
if name in self._updated:
return self._updated[name]
return self._db[name]
def set(self, name, value):
"""Sets parameter |name| to |value|.
Note that this function does not flush these parameter values to main.cf;
To do that, use |flush|.
:param str name: The name of the parameter to set.
:param str value: The value of the parameter.
"""
if name not in self._db:
return # TODO: error here
# We've updated this name before.
if name in self._updated:
if value == self._updated[name]:
return
if value == self._db[name]:
del self._updated[name]
return
# We haven't updated this name before.
else:
# If we're just setting the default value, ignore.
if value != self._db[name]:
self._updated[name] = value
def flush(self):
"""Flushes all parameter changes made using "self.set" to "main.cf".
:raises error.PluginError: When we can't flush to main.cf.
"""
if len(self._updated) == 0:
return
args = ['-e']
for name, value in self._updated.iteritems():
args.append('{0}={1}'.format(name, value))
try:
return self._get_output(args)
except:
raise errors.PluginError("Unable to save to Postfix config!")
def _call(self, extra_args=None):
"""Runs Postconf and returns the result.
If self._modifiers is set, it is provided on the command line to
postconf before any values in extra_args.
:param list extra_args: additional arguments for the command
:returns: data written to stdout and stderr
:rtype: `tuple` of `str`
:raises subprocess.CalledProcessError: if the command fails
"""
all_extra_args = []
for args_list in (self._modifiers, extra_args,):
if args_list is not None:
all_extra_args.extend(args_list)
return super(ConfigMain, self)._call(all_extra_args)
def _parse_main_output(output):
"""Parses the raw output from Postconf about main.cf.
:param str output: data postconf wrote to stdout about main.cf
:returns: generator providing key-value pairs from main.cf
:rtype: generator
"""
for line in output.splitlines():
name, _, value = line.partition(" =")
yield name, value.strip()