VirtualMailManager/ext/postconf.py
changeset 760 b678a1c43027
parent 748 659c4476c57c
child 761 e4e656f19771
equal deleted inserted replaced
748:659c4476c57c 760:b678a1c43027
     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 _