diff options
author | Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> | 2010-08-26 10:17:37 +0100 |
---|---|---|
committer | Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> | 2010-08-26 10:17:37 +0100 |
commit | e2f75e06656c1bd0cd0cecb4a99b8220f468fd8d (patch) | |
tree | f0ac19bdd7be13845c8a706df50f37333bf02a86 /pykolab | |
download | pykolab-e2f75e06656c1bd0cd0cecb4a99b8220f468fd8d.tar.gz |
Initial commit
Diffstat (limited to 'pykolab')
-rw-r--r-- | pykolab/__init__.py.in | 40 | ||||
-rw-r--r-- | pykolab/base.py | 69 | ||||
-rw-r--r-- | pykolab/conf/__init__.py | 266 | ||||
-rw-r--r-- | pykolab/conf/defaults.py | 38 | ||||
-rw-r--r-- | pykolab/conf/runtime.py | 23 | ||||
-rw-r--r-- | pykolab/constants.py | 71 | ||||
-rw-r--r-- | pykolab/logger.py | 93 | ||||
-rw-r--r-- | pykolab/plugins.py | 216 | ||||
-rw-r--r-- | pykolab/setup/__init__.py | 31 | ||||
-rw-r--r-- | pykolab/setup/imap.py | 29 | ||||
-rw-r--r-- | pykolab/setup/ldap_setup.py | 140 | ||||
-rw-r--r-- | pykolab/translate.py | 47 | ||||
-rw-r--r-- | pykolab/utils.py | 76 |
13 files changed, 1139 insertions, 0 deletions
diff --git a/pykolab/__init__.py.in b/pykolab/__init__.py.in new file mode 100644 index 0000000..056f3c6 --- /dev/null +++ b/pykolab/__init__.py.in @@ -0,0 +1,40 @@ +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +__license__ = "GPLv2+" +__copyright__ = "Kolab Systems AG" +__version__ = @VERSION@ +__release__ = @RELEASE@ + +if @RELEASE@ < 1: + __status__ = 'snapshot' +elif math.round(@RELEASE@,0) < @RELEASE@: + __status__ = 'prerelease' +else: + __status__ = 'stable' + +import traceback +import shutil +import sys + +import pykolab +import pykolab.plugins + +from pykolab.translate import _ + +from pykolab.conf import Conf diff --git a/pykolab/base.py b/pykolab/base.py new file mode 100644 index 0000000..224d466 --- /dev/null +++ b/pykolab/base.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +from pykolab.conf import Defaults, Runtime +import pykolab.conf + +class PyKolabBase(object): + + def __init__(self, pykolab): + """ + Initializes the a PyKolab class with the options specified from the command line. + Launches our plugin detection. + Creates a logger instance + Creates a configuration store + Detects whether we are in CLI or GUI mode + Sets the logger configuration + Sets up the final configuration store + """ + + # Get the options parser, it's valuable ;-) + self.parser = revisor.parser + + # The options it has defined are valuable too + self.cli_options = revisor.cli_options + self.plugins = revisor.plugins + self.plugins.base = self + + # At this point, 'self' isn't much yet, so: + # first create a simple logger instance that won't do much, + # then create a configuration store with that logger, + # then start detecting the mode that we are in (GUI / CLI), + # then let the logger know about the configuration store, + # then /really/ set up the configuration store (now that it has a + # valid logger that knows about the configuration store), + # + # Create logger + self.create_logger() + + # Create ConfigStore (it needs the logger to be created!) + self.create_configstore() + + # Detect our mode (options or try/except) + self.detect_mode() + + # Let the logger know about cfg (it needs a ConfigStore instance!) + self.log.set_config(self.cfg) + + # Then really setup the ConfigStore (because that needs a logger!) + self.cfg.setup_cfg() + + misc.check_selinux(log=self.log) + + diff --git a/pykolab/conf/__init__.py b/pykolab/conf/__init__.py new file mode 100644 index 0000000..66be1b3 --- /dev/null +++ b/pykolab/conf/__init__.py @@ -0,0 +1,266 @@ +# -*- coding: utf-8 -*- +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +import logging +import os +import sys + +from optparse import OptionParser +from ConfigParser import SafeConfigParser + +import pykolab +from pykolab.conf.defaults import Defaults +from pykolab.conf.runtime import Runtime +from pykolab.constants import * +from pykolab.translate import _ + +class Conf(object): + def __init__(self): + """ + self.args == Arguments passed on the CLI + self.cli_options == Parser results (again, CLI) + self.parser == The actual Parser (from OptionParser) + self.plugins == Our Kolab Plugins + """ + + self.args = None + self.cli_options = None + self.parser = None + self.plugins = None + + # The location where our configuration parser is going to end up + self.cfg_parser = None + + # Create and parse the options + self.parse_options() + + # At this point, 'self' isn't much yet, so: + # first create a simple logger instance that won't do much, + # then create a configuration store with that logger, + # then start detecting the mode that we are in (GUI / CLI), + # then let the logger know about the configuration store, + # then /really/ set up the configuration store (now that it has a + # valid logger that knows about the configuration store), + # + # Create logger + self.create_logger() + + # Let the logger know about cfg (it needs a ConfigStore instance!) + self.log.set_config(self) + + # The defaults can some from; + # - a file we ship with the packages + # - a customly supplied file (by customer) + # - a file we write out + # - this python class + # + # Look, we want defaults + self.defaults = Defaults(self.plugins) + + # This is where we check our parser for the defaults being set there. + self.set_defaults_from_cli_options() + + # But, they should be available in our class as well + for option in self.defaults.__dict__.keys(): + setattr(self,option,self.defaults.__dict__[option]) + + # There is also a number of runtime specific variables + self.runtime = Runtime(self.plugins, self.defaults) + + # Which should also be available here + for option in self.runtime.__dict__.keys(): + self.log.debug(_("Setting %s to %r") % (option, self.runtime.__dict__[option]), level=9) + setattr(self,option,self.runtime.__dict__[option]) + + def parse_options(self, load_plugins=True): + """ + Create the OptionParser for the options passed to us from runtime + Command Line Interface. + """ + + # Enterprise Linux 5 does not have an "epilog" parameter to OptionParser + try: + self.parser = OptionParser(epilog=epilog) + except: + self.parser = OptionParser() + + ## + ## Runtime Options + ## + runtime_group = self.parser.add_option_group(_("Runtime Options")) + runtime_group.add_option( "-c", "--config", + dest = "config_file", + action = "store", + default = "/etc/kolab/kolab.conf", + help = _("Configuration file to use")) + + runtime_group.add_option( "-d", "--debug", + dest = "debuglevel", + type = 'int', + default = 0, + help = _("Set the debugging verbosity. Maximum is 99")) + + runtime_group.add_option( "--logfile", + dest = "logfile", + action = "store", + default = "/var/log/kolabd/kolabd.log", + help = _("Log file to use")) + + runtime_group.add_option( "-y", "--yes", + dest = "answer_yes", + action = "store_true", + default = False, + help = _("Configuration file to use")) + + ## + ## Get options from plugins + ## + if load_plugins: + self.plugins = pykolab.plugins.KolabPlugins(init=True) + self.plugins.add_options(self.parser) + + # Parse Options + (self.cli_options, self.args) = self.parser.parse_args() + + def run(self): + """ + Run Forest, RUN! + """ + exitcode = 0 + + if len(self.args) >= 1: + if hasattr(self,"command_%s" % self.args[0].replace('-','_')): + exec("self.command_%s(%r)" % (self.args[0].replace('-','_'), self.args[1:])) + else: + print >> sys.stderr, _("No command supplied") + + + def command_dump(self, *args, **kw): + """ + Dumps applicable, valid configuration that is not defaults. + """ + + if not self.cfg_parser: + self.read_config() + + if not self.cfg_parser.has_section('kolab'): + print "No section found for kolab" + sys.exit(1) + + # Get the sections, and then walk through the sections in a + # sensible way. + items = self.cfg_parser.options('kolab') + + items.sort() + + for item in items: + mode = self.cfg_parser.get('kolab',item) + print "%s = %s" %(item,mode) + + if not self.cfg_parser.has_section(mode): + print "WARNING: No configuratino section for %s: %s" %(item,mode,) + continue + + keys = self.cfg_parser.options(mode) + keys.sort() + + if self.cfg_parser.has_option(mode, 'leave_this_one_to_me'): + print "Ignoring section %s" %(mode,) + continue + + for key in keys: + print "%s_%s = %s" %(mode, key ,self.cfg_parser.get(mode,key)) + + def read_config(self): + """ + Reads the configuration file, sets a self.cfg_parser. + """ + + self.cfg_parser = SafeConfigParser() + self.cfg_parser.read(self.cli_options.config_file) + + def command_get(self, *args, **kw): + """ + Get a configuration option. + + Pass me a section and key please. + """ + exec("args = %r" % args) + + if not self.cfg_parser: + self.read_config() + + if len(args) == 1: + self.log.error(_("Only one option supplied"), recoverable=False) + + if len(args) == 2: + if self.cfg_parser.has_option(args[0], args[1]): + print "%s/%s: %r" %(args[0],args[1],self.cfg_parser.get(args[0],args[1])) + else: + self.log.warning(_("Option does not exist in config file, pulling from defaults")) + print "Something default" + +# if len(args) == 3: +# # Return non-zero if no match +# # Return zero if match +# # Improvised "check" function + + def command_set(self, *args, **kw): + """ + Set a configuration option. + + Pass me a section, key and value please. Note that the section should + already exist. + + TODO: Add a strict parameter + TODO: Add key value checking + """ + exec("args = %r" % args) + + if not self.cfg_parser: + self.read_config() + + if not len(args) == 3: + self.log.error(_("Insufficient options. Need section, key and value -in that order."), recoverable=False) + + if not self.cfg_parser.has_section(args[0]): + self.log.error(_("No section '%s' exists.") %(args[0])) + + self.cfg_parser.set(args[0], args[1], args[2]) + fp = open(self.cli_options.config_file, "w+") + self.cfg_parser.write(fp) + fp.close() + + def create_logger(self): + """Create a logger instance using cli_options.debuglevel""" + if not self.cli_options.debuglevel == None: + loglevel = logging.DEBUG + else: + loglevel = logging.INFO + self.cli_options.debuglevel = 0 + + # Initialize logger + self.log = pykolab.logger.Logger(loglevel=loglevel, debuglevel=self.cli_options.debuglevel, logfile=self.cli_options.logfile) + + def set_defaults_from_cli_options(self): + for long_opt in self.parser.__dict__['_long_opt'].keys(): + if long_opt == "--help": + continue + setattr(self.defaults,self.parser._long_opt[long_opt].dest,self.parser._long_opt[long_opt].default) + diff --git a/pykolab/conf/defaults.py b/pykolab/conf/defaults.py new file mode 100644 index 0000000..ba0cbce --- /dev/null +++ b/pykolab/conf/defaults.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +class Defaults(object): + def __init__(self, plugins=None): + # Each possible section in the configuration has a dict here. + + # The default authentication mechanism + self.kolab = { + 'auth_mechanism': 'ldap', + } + + # The default LDAP URI. Note that these are + # prefixed with the section name. + self.ldap = { + 'uri': "ldap://localhost", + 'base_dn': "dc=localhost,dc=localdomain", + 'bind_dn': "", + 'bind_pw': "", + 'user_base_dn': "ou=People,%(base_dn)s", + 'group_base_dn': "ou=Groups,%(base_dn)s" + } diff --git a/pykolab/conf/runtime.py b/pykolab/conf/runtime.py new file mode 100644 index 0000000..b4a7af1 --- /dev/null +++ b/pykolab/conf/runtime.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +class Runtime(object): + def __init__(self, plugins, defaults): + pass + diff --git a/pykolab/constants.py b/pykolab/constants.py new file mode 100644 index 0000000..84d4a32 --- /dev/null +++ b/pykolab/constants.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +import socket +import sys + +from pykolab.translate import _ + +domain = 'pykolab' + +epilog = _( "PyKolab is a Kolab Systems product. For more information " + \ + "about Kolab or PyKolab, visit http://www.kolabsys.com") + +COMPONENTS = [ + 'imap', + 'ldap', + 'mta' + ] + +hostname = socket.gethostname() +fqdn = socket.getfqdn() +try: + domain_parts = fqdn.split('.') + if len(domain_parts) < 3: + print >> sys.stderr, _("WARNING") + ": " + _("The Fully Qualified " + \ + "Domain Name or FQDN for this system is incorrect. Falling " + \ + "back to 'localdomain'.") + domainname = "localdomain" + else: + domainname = '.'.join(domain_parts[1:]) +except IndexError: + domainname = "localdomain" + +# The system RC directory +RC_DIR = "/etc/rc.d/init.d/" + +# Service map; +# +# Convert names of registered system services to their type. For example, +# on Red Hat, OpenLDAP is 'slapd', whereas on Debian, OpenLDAP is 'ldap'. +# +SERVICE_MAP = { + 'dirsrv': { + 'type': '389ds', + 'description': _('389 Directory Server or Red Hat Directory Server') + }, + 'ldap': { + 'type': 'openldap', + 'description': _('OpenLDAP or compatible') + }, + 'slapd': { + 'type': 'openldap', + 'description': _('OpenLDAP or compatible') + }, + }
\ No newline at end of file diff --git a/pykolab/logger.py b/pykolab/logger.py new file mode 100644 index 0000000..168b338 --- /dev/null +++ b/pykolab/logger.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +import logging +import logging.handlers +import sys + +# Translation +from pykolab.translate import _, N_ + +class Logger: + def __init__(self, loglevel=logging.INFO, debuglevel=0, logfile="/var/log/kolab/kolabd.log"): + self.loglevel = loglevel + self.debuglevel = debuglevel + + plaintextformatter = logging.Formatter("%(message)s") + + console_stdout = logging.StreamHandler(sys.stdout) + console_stdout.setFormatter(plaintextformatter) + + try: + filelog_handler = logging.FileHandler(filename=logfile) + filelog_handler.setFormatter(plaintextformatter) + except IOError, e: + print >> sys.stderr, _("Cannot log to file %s: %s") % (logfile, e) + + self.log = logging.getLogger() + self.log.addHandler(console_stdout) + try: + self.log.addHandler(filelog_handler) + except: + pass + + self.log.setLevel(self.loglevel) + + def set_config(self, cfg): + """Let the Logger instance know what our configuration is and she might + be able to distinct between CLI and GUI mode, or even give more details + about what goes wrong""" + self.cfg = cfg + + def info(self, msg): + self.log.info(msg) + + def debug(self, msg, level=1): + # By default, level=1 so that debug messages are suppressed + if level <= self.debuglevel: + self.log.debug(msg) + + def error(self, msg, recoverable=True): + self.log.error(msg) + if recoverable: + self.error_prompt(msg) + else: + sys.exit(1) + + def warning(self, msg): + self.log.warning(msg) + self.warning_prompt(msg) + + def error_prompt(self, text): + """The error has already been logged to the console, try and catch some input""" + if not self.cfg.answer_yes: + sys.stderr.write(_("Do you want to continue? [Y/n]") + " ") + answer = sys.stdin.readline()[:-1] + if answer == "n": + self.error(_("Abort! Abort! Abort!"), recoverable=False) + sys.exit(1) + + def warning_prompt(self, text): + """The error has already been logged to the console, try and catch some input""" + if not self.cfg.answer_yes: + sys.stdout.write(_("Do you want to continue? [Y/n]") + " ") + answer = sys.stdin.readline()[:-1] + if answer == "n": + self.error(_("Abort! Abort! Abort!"), recoverable=False) + sys.exit(1) diff --git a/pykolab/plugins.py b/pykolab/plugins.py new file mode 100644 index 0000000..5d0e012 --- /dev/null +++ b/pykolab/plugins.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2007-2010 Fedora Unity Project (http://fedoraunity.org) +# +# Jonathan Steffan <jon a fedoraunity.org> +# Jeroen van Meeuwen <kanarip a fedoraunity.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import logging +import os +import pykolab +import sys +import pdb + +# Translation +from pykolab.translate import _ + +class KolabPlugins: + """Detects, loads and interfaces with plugins for Kolab""" + def __init__(self, init=False): + """ + Searches the plugin directory for plugins, and loads them into a list. + """ + self.plugins = {} + + for plugin_path in [ '/usr/share/pykolab/plugins/', './plugins/' ]: + if os.path.isdir(plugin_path): + for plugin in os.listdir(plugin_path): + if os.path.isdir('%s/%s/' % (plugin_path,plugin,)): + self.plugins[plugin] = False + + self.check_plugins(init=init) + + def load_plugins(self, plugins=[], init=False): + """Loads plugins specified by a list of plugins or loads them all""" + if len(plugins) < 1: + plugins = self.plugins.keys() + + for plugin in plugins: + if self.plugins[plugin]: + try: + exec("self.%s = revisor.%s.Revisor%s()" % (plugin,plugin,plugin.replace("mod","").capitalize())) + except Exception, e: + if not init: print >> sys.stderr, _("Plugin %s failed to load (%s: %s)") % (plugin, e.__class__, e) + + def check_plugins(self, init=False): + """Checks all plugins in self.plugins and sets the values to + True (loadable) or False (not enabled, not installed or not loadable)""" + for plugin in self.plugins: + try: + exec("import revisor.%s" % plugin) + self.plugins[plugin] = True + self.load_plugins(plugins=[plugin], init=init) + except ImportError, e: + if not init: print >> sys.stderr, _("ImportError for plugin %s: %s") % (plugin,e) + self.plugins[plugin] = False + except RuntimeError, e: + if not init: print >> sys.stderr, _("RuntimeError for plugin %s: %s") % (plugin,e) + self.plugins[plugin] = False + except Exception, e: + if not init: print >> sys.stderr, _("Plugin %s failed to load (%s: %s)") % (plugin, e.__class__, e) + + def set_defaults(self, defaults, plugins=[]): + """Test for a function set_defaults() in all available and loaded plugins and execute plugin.set_defaults()""" + if len(plugins) < 1: + plugins = self.plugins.keys() + + for plugin in plugins: + if not self.plugins[plugin]: + continue + if not hasattr(self,plugin): + continue + + if hasattr(getattr(self,plugin),"set_defaults"): + try: + getattr(self,plugin).set_defaults(defaults) + except TypeError, e: + print >> sys.stderr, _("Cannot set defaults for plugin %s: %s") % (plugin,e) + except RuntimeError, e: + print >> sys.stderr, _("Cannot set defaults for plugin %s: %s") % (plugin,e) + except: + print >> sys.stderr, _("Cannot set defaults for plugin %s: Unknown Error") % (plugin) + + else: + print >> sys.stderr, _("Not setting defaults for plugin %s: No function 'set_defaults()'") % plugin + + def set_runtime(self, runtime, plugins=[]): + """Set runtime variables from plugins, like 'i_did_all_this'""" + if len(plugins) < 1: + plugins = self.plugins.keys() + + for plugin in plugins: + if not self.plugins[plugin]: + continue + if not hasattr(self,plugin): + continue + + if hasattr(getattr(self,plugin),"set_runtime"): + try: + getattr(self,plugin).set_runtime(runtime) + except RuntimeError, e: + print >> sys.stderr, _("Cannot set runtime for plugin %s: %s") % (plugin,e) + else: + print >> sys.stderr, _("Not setting runtime for plugin %s: No function 'set_runtime()'") % plugin + + def add_options(self, parser, plugins=[]): + """Add options specified in a plugin to parser. Takes a list of plugin names or does them all""" + if len(plugins) < 1: + plugins = self.plugins.keys() + + for plugin in plugins: + if not self.plugins[plugin]: + continue + if not hasattr(self,plugin): + continue + + if hasattr(getattr(self,plugin),"add_options"): + try: + exec("self.%s.add_options(parser)" % plugin) + except RuntimeError, e: + print >> sys.stderr, _("Cannot add options for plugin %s: %s") % (plugin,e) + else: + print >> sys.stderr, _("Not adding options for plugin %s: No function 'add_options()'") % plugin + + def check_options(self, cfg, plugins=[]): + """Executes plugin.check_plugins() for all enabled plugins or the list of plugin names specified.""" + + if len(plugins) < 1: + plugins = self.plugins.keys() + + for plugin in plugins: + if not self.plugins[plugin]: + continue + if not hasattr(self,plugin): + continue + + if hasattr(getattr(self,plugin),"check_options"): + try: + exec("self.%s.check_options(cfg, cfg.cli_options)" % plugin) + except AttributeError, e: + print >> sys.stderr, _("Cannot check options for plugin %s: %s") % (plugin,e) + else: + print >> sys.stderr, _("Not checking options for plugin %s: No function 'check_options()'") % plugin + + def plugin_check_setting(self, func, option, val, plugins=[]): + """Checks one setting specified by 'option' against the 'val' it is passed by all plugins or by the list of plugins specified""" + + if len(plugins) < 1: + plugins = self.plugins.keys() + + for plugin in plugins: + if not self.plugins[plugin]: + continue + if not hasattr(self,plugin): + continue + + if hasattr(getattr(self,plugin),"%s_%s" % (func,option)): + exec("retval = getattr(self,plugin).%s_%s(val)" % (func,option)) + return retval + + return False + + def exec_hook(self, hook, plugins=[]): + """Execute a hook""" + + if len(plugins) < 1: + plugins = self.plugins.keys() + + for plugin in plugins: + if not self.plugins[plugin]: + continue + if not hasattr(self,plugin): + continue + + if hasattr(getattr(self,plugin),hook): + try: + exec("self.%s.%s()" % (plugin,hook)) + except AttributeError, e: + print >> sys.stderr, _("Cannot execute hook %s for plugin %s: %s") % (hook,plugin,e) + + def return_true_boolean_from_plugins(self, bool, plugins=[]): + """Given the name of a boolean, walks all specified plugins, or all available plugins, and returns True if a plugin has it set to true""" + if len(plugins) < 1: + plugins = self.plugins.keys() + + retval = False + + for plugin in plugins: + if not self.plugins[plugin]: + continue + if not hasattr(self,plugin): + continue + + if hasattr(getattr(self,plugin),bool): + try: + exec("boolval = self.%s.%s" % (plugin,bool)) + except AttributeError, e: + pass + else: + boolval = None + + if boolval: retval = True + + return retval diff --git a/pykolab/setup/__init__.py b/pykolab/setup/__init__.py new file mode 100644 index 0000000..73859fb --- /dev/null +++ b/pykolab/setup/__init__.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +from pykolab import constants + +__all__ = [ + ] + +for component in constants.COMPONENTS: + try: + exec("from %s_setup import setup as %s_setup" % (component,component)) + __all__.append("%s_setup" % component) + except: + pass diff --git a/pykolab/setup/imap.py b/pykolab/setup/imap.py new file mode 100644 index 0000000..6165259 --- /dev/null +++ b/pykolab/setup/imap.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +import logging +import os +import sys + +from pykolab.translate import _ +from pykolab import utils + +def setup(): + print "I'm in the IMAP setup"
\ No newline at end of file diff --git a/pykolab/setup/ldap_setup.py b/pykolab/setup/ldap_setup.py new file mode 100644 index 0000000..f381711 --- /dev/null +++ b/pykolab/setup/ldap_setup.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +import getpass +import ldap +import logging +import os +import sys + +from pykolab.translate import _ +from pykolab import constants +from pykolab import utils + +def setup(): + """ + Setup LDAP from here. + + # Register with existing LDAP tree? + #* Verify schema loaded + #* Forget about flexibility + # Create new LDAP tree + #* OpenLDAP + """ + + (service, other_services) = utils.is_service([ + 'dirsrv', + 'ldap', + 'slapd' + ]) + + for item in other_services: + print >> sys.stderr, _("Warning: LDAP Service '%s' is available on " + \ + "this system as well.") % item + + print _("Found system service %s.") % service + + #ldap_uri = utils.ask_question(_("LDAP URI (read/write)"), "ldap://ldap.%s" %(constants.domainname)) + ldap_uri = utils.ask_question(_("LDAP URI (read/write)"), "ldap://localhost") + manager_dn = utils.ask_question("Manager DN", "cn=Directory Manager") + #manager_pw = utils.ask_question("Manager Password", password=True) + manager_pw = utils.ask_question("Manager Password", "verysecret", password=True) + + try: + con = ldap.initialize(ldap_uri) + con.bind(manager_dn, manager_pw, ldap.AUTH_SIMPLE) + except TypeError: + # This is a funny input error ("") + print >> sys.stderr, _("Could not connect to LDAP server due to " + \ + "invalid LDAP URI format or no local socket") + sys.exit(1) + except ldap.INVALID_CREDENTIALS, e: + print >> sys.stderr, _("Your username or password are incorrect") + sys.exit(1) + except ldap.LDAPError, e: + print >> sys.stderr, _("Could not connect to LDAP server due to " + \ + "invalid LDAP URI (or invalid format) or no local socket") + sys.exit(1) + except ldap.SERVER_DOWN, e: + print >> sys.stderr, e['desc'] + sys.exit(1) + + # Returns a list of dicts (empty list if not found) + kolab_config_dn_results = con.search_s('cn=kolab,cn=config', ldap.SCOPE_SUBTREE, '(cn=kolab)', ['cn']) + + if len(kolab_config_dn_results) == 1: + print >> sys.stdout, "Success: Found cn=kolab,cn=config" + + else: + initialize_kolab_config_dn(con) + + #if not service == "": + #if service in constants.SERVICE_MAP.keys(): + #exec("setup_%s()" % constants.SERVICE_MAP['%s' % service]['type']) + #else: + ## No service found on the local system, so ask a bunch of questions. + ## + ## - ldap uri + ## - manager dn + ## - manager pw + #pass + +def setup_389ds(): + """ + Executes for a local 389 Directory Server installation. + """ + + for (path, directories, files) in os.walk("/etc/dirsrv/"): + for directory in directories: + if directory.startswith('slapd-'): + print "Found a dirsrv instance %r" % directory + dirsrv_instance = directory + +# if dirsrv_instance == '': +# # Apparently we're working with a remote dirsrv... are we going to have +# # to set up the local directory service as well?? +# raise NotImplementedError, _("Initializing a 389 Directory Server has not been implemented yet. Please use setup-ds-admin") +# +# elif dirsrv_instance == 'slapd-localhost': +# # The server is on localhost +# ldap_conn = ldap.initialize(uri="ldap://localhost:389") +# try: +# ldap_conn.start_tls_s() +# except ldap.LDAPError, e: +# pass +# +# else: +# pass + +def setup_openldap(): + print "im an openldap system!" + + +def initialize_kolab_config_dn(ldap_con=None): + if ldap_con == None: + return + + ldif = """ +dn: cn=kolab,cn=config +cirUpdateSchedule: New +cn: kolab +objectClass: top +objectClass: extensibleobject +""" diff --git a/pykolab/translate.py b/pykolab/translate.py new file mode 100644 index 0000000..6386912 --- /dev/null +++ b/pykolab/translate.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Copyright 2010 Kolab Systems AG (http://www.kolabsys.com) +# +# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 only +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +try: + from pykolab.constants import domain +except ImportError: + domain = 'pykolab' + +import gettext +import os + +N_ = lambda x: x +_ = lambda x: gettext.ldgettext(domain, x) + +def getDefaultLangs(): + languages = [] + for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): + val = os.environ.get(envar) + if val: + languages = val.split(':') + break + if 'C' not in languages: + languages.append('C') + + # now normalize and expand the languages + nelangs = [] + for lang in languages: + for nelang in gettext._expand_lang(lang): + if nelang not in nelangs: + nelangs.append(nelang) + return nelangs diff --git a/pykolab/utils.py b/pykolab/utils.py new file mode 100644 index 0000000..a5c0f1f --- /dev/null +++ b/pykolab/utils.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +import getpass +import os + +from pykolab import constants + +def ask_question(question, default="", password=False): + + if password: + answer = getpass.getpass("%s: " %(question)) + else: + if default == "": + answer = raw_input("%s: " %(question)) + else: + answer = raw_input("%s [%s]: " %(question, default)) + + if answer == "": + return default + else: + return answer + +def parse_input(_input, splitchars= [ ' ' ]): + """ + Split the input string using the split characters defined + in splitchars, and remove the empty list items, then unique the + list items. + + Takes a string as input, and a list of characters the string should be + split with (list of delimiter characters). + """ + + _parse_list = _input.split(splitchars.pop()) + _output_list = [] + + for splitchar in splitchars: + __parse_list = [] + for item in _parse_list: + __parse_list.extend(item.split(splitchar)) + _parse_list = __parse_list + + for item in _parse_list: + if not item == '': + if _output_list.count(item) < 1: + _output_list.append(item) + + return _output_list + +def pop_empty_from_list(_input_list): + _output_list = [] + + for item in _input_list: + if not item == '': + _output_list.append(item) + +def is_service(services): + """ + Checks each item in list services to see if it has a RC script in + constants.RC_DIR to see if it's a service, and returns + the name of the service for the first service it can find. However, + it also checks whether the other services exist and issues a warning if + more then one service exists. + + Usage: utils.is_service(['dirsrv', 'ldap']) + """ + _service = '' + _other_services = [] + + for service in services: + if os.path.isfile(os.path.join(constants.RC_DIR, service)): + if _service == '': + _service = service + else: + _other_services.append(service) + + return (_service,_other_services) |