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