1 # -*- coding: UTF-8 -*- |
|
2 # Copyright (c) 2008 - 2014, Pascal Volk |
|
3 # See COPYING for distribution information. |
|
4 """ |
|
5 VirtualMailManager.ext.postconf |
|
6 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
7 |
|
8 Wrapper class for Postfix's postconf. |
|
9 Postconf instances can be used to read actual values of configuration |
|
10 parameters or edit the value of a configuration parameter. |
|
11 |
|
12 postconf.read(parameter) -> value |
|
13 postconf.edit(parameter, value) |
|
14 """ |
|
15 |
|
16 import re |
|
17 from subprocess import Popen, PIPE |
|
18 |
|
19 from VirtualMailManager.errors import VMMError |
|
20 from VirtualMailManager.constants import VMM_ERROR |
|
21 |
|
22 _ = lambda msg: msg |
|
23 |
|
24 |
|
25 class Postconf(object): |
|
26 """Wrapper class for Postfix's postconf.""" |
|
27 __slots__ = ('_bin', '_val') |
|
28 _parameter_re = re.compile(r'^\w+$') |
|
29 _variables_re = re.compile(r'\$\b\w+\b') |
|
30 |
|
31 def __init__(self, postconf_bin): |
|
32 """Creates a new Postconf instance. |
|
33 |
|
34 Argument: |
|
35 |
|
36 `postconf_bin` : str |
|
37 absolute path to the Postfix postconf binary. |
|
38 """ |
|
39 self._bin = postconf_bin |
|
40 self._val = '' |
|
41 |
|
42 def edit(self, parameter, value): |
|
43 """Set the `parameter`'s value to `value`. |
|
44 |
|
45 Arguments: |
|
46 |
|
47 `parameter` : str |
|
48 the name of a Postfix configuration parameter |
|
49 `value` : str |
|
50 the parameter's new value. |
|
51 """ |
|
52 self._check_parameter(parameter) |
|
53 stderr = Popen((self._bin, '-e', parameter + '=' + str(value)), |
|
54 stderr=PIPE).communicate()[1] |
|
55 if stderr: |
|
56 raise VMMError(stderr.strip(), VMM_ERROR) |
|
57 |
|
58 def read(self, parameter, expand_vars=True): |
|
59 """Returns the parameters value. |
|
60 |
|
61 If expand_vars is True (default), all variables in the value will be |
|
62 expanded: |
|
63 e.g. mydestination: mail.example.com, localhost.example.com, localhost |
|
64 Otherwise the value may contain one or more variables. |
|
65 e.g. mydestination: $myhostname, localhost.$mydomain, localhost |
|
66 |
|
67 Arguments: |
|
68 |
|
69 `parameter` : str |
|
70 the name of a Postfix configuration parameter. |
|
71 `expand_vars` : bool |
|
72 indicates if variables should be expanded or not, default True |
|
73 """ |
|
74 self._check_parameter(parameter) |
|
75 self._val = self._read(parameter) |
|
76 if expand_vars: |
|
77 self._expand_vars() |
|
78 return self._val |
|
79 |
|
80 def _check_parameter(self, parameter): |
|
81 """Check that the `parameter` looks like a configuration parameter. |
|
82 If not, a VMMError will be raised.""" |
|
83 if not self.__class__._parameter_re.match(parameter): |
|
84 raise VMMError(_(u"The value '%s' does not look like a valid " |
|
85 u"Postfix configuration parameter name.") % |
|
86 parameter, VMM_ERROR) |
|
87 |
|
88 def _expand_vars(self): |
|
89 """Expand the $variables in self._val to their values.""" |
|
90 while True: |
|
91 pvars = set(self.__class__._variables_re.findall(self._val)) |
|
92 if not pvars: |
|
93 break |
|
94 if len(pvars) > 1: |
|
95 self._expand_multi_vars(self._read_multi(pvars)) |
|
96 continue |
|
97 pvars = pvars.pop() |
|
98 self._val = self._val.replace(pvars, self._read(pvars[1:])) |
|
99 |
|
100 def _expand_multi_vars(self, old_new): |
|
101 """Replace all $vars in self._val with their values.""" |
|
102 for old, new in old_new.iteritems(): |
|
103 self._val = self._val.replace('$' + old, new) |
|
104 |
|
105 def _read(self, parameter): |
|
106 """Ask postconf for the value of a single configuration parameter.""" |
|
107 stdout, stderr = Popen([self._bin, '-h', parameter], stdout=PIPE, |
|
108 stderr=PIPE).communicate() |
|
109 if stderr: |
|
110 raise VMMError(stderr.strip(), VMM_ERROR) |
|
111 return stdout.strip() |
|
112 |
|
113 def _read_multi(self, parameters): |
|
114 """Ask postconf for multiple configuration parameters. Returns a dict |
|
115 parameter: value items.""" |
|
116 cmd = [self._bin] |
|
117 cmd.extend(parameter[1:] for parameter in parameters) |
|
118 stdout, stderr = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() |
|
119 if stderr: |
|
120 raise VMMError(stderr.strip(), VMM_ERROR) |
|
121 par_val = {} |
|
122 for line in stdout.splitlines(): |
|
123 par, val = line.split(' = ') |
|
124 par_val[par] = val |
|
125 return par_val |
|
126 |
|
127 del _ |
|