]> Frank Brehm's Git Trees - pixelpark/admin-tools.git/commitdiff
Adding and using pp_lib/mk_home_app.py
authorFrank Brehm <frank.brehm@pixelpark.com>
Mon, 20 Mar 2017 10:22:27 +0000 (11:22 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Mon, 20 Mar 2017 10:22:27 +0000 (11:22 +0100)
etc/mk-home.ini.default
mk-home
pp_lib/ldap_app.py
pp_lib/mk_home_app.py [new file with mode: 0644]

index 214abeb3875354559c46f0c88e6d6111b7ae29af..e87570aa6509fbf63ca03e5a0540f82d5b106865 100644 (file)
@@ -9,4 +9,8 @@
 bind_dn = cn=admin
 #bind_pw = <LDAP admin password>
 
+[mk-home]
+initial_uid = 999999999
+chroot_homedir = '/mnt/nfs/home'
+
 # vim: filetype=dosini
diff --git a/mk-home b/mk-home
index fe02a25f850c3a6a8829807b55a848df8afaaf91..dec4def6db15bf02d65d2301ff0ffc23622b5310 100755 (executable)
--- a/mk-home
+++ b/mk-home
@@ -17,7 +17,7 @@ if os.path.exists(os.path.join(cur_dir, 'pp_lib')):
 
 from pp_lib.common import pp
 
-from pp_lib.ldap_app import PpLdapApplication
+from pp_lib.mk_home_app import PpMkHomeApp
 
 log = logging.getLogger(__name__)
 
@@ -28,7 +28,7 @@ appname = os.path.basename(sys.argv[0])
 
 locale.setlocale(locale.LC_ALL, '')
 
-app = PpLdapApplication(appname=appname, cfg_stems='mk-home')
+app = PpMkHomeApp(appname=appname)
 app.initialized = True
 
 if app.verbose > 2:
index e14aac1316cccce8290a1d04213aaa3fe6dd16df..22d2df2905db25db5071e2b4ed5272b2f298eac6 100644 (file)
@@ -36,7 +36,7 @@ from .merge import merge_structure
 
 from .cfg_app import PpCfgAppError, PpConfigApplication
 
-__version__ = '0.3.2'
+__version__ = '0.3.4'
 LOG = logging.getLogger(__name__)
 
 
@@ -51,7 +51,7 @@ class PpLdapAppError(PpCfgAppError):
 # =============================================================================
 class PpLdapApplication(PpConfigApplication):
     """
-    Class for configured application objects.
+    Class for a LDAP based configured application objects.
     """
 
     default_ldap_hosts = [
@@ -118,11 +118,8 @@ class PpLdapApplication(PpConfigApplication):
             cfg_encoding=cfg_encoding, need_config_file=need_config_file,
         )
 
-        pass
-
     # -------------------------------------------------------------------------
     def perform_config(self):
-
         """
         Execute some actions after reading the configuration.
 
@@ -131,11 +128,15 @@ class PpLdapApplication(PpConfigApplication):
         """
 
         got_host = False
-        for section in self.cfg.keys():
+        for section_name in self.cfg.keys():
 
-            if not section.lower() == 'ldap':
+            if not section_name.lower() == 'ldap':
                 continue
-            ldap_section = self.cfg[section]
+            ldap_section = self.cfg[section_name]
+            if self.verbose > 2:
+                LOG.debug("Evaluating config section {n!r}:\n{s}".format(
+                    n=section_name, s=pp(ldap_section)))
+
 
             if 'host' in ldap_section:
                 hosts = self.fs_re.split(ldap_section['host'])
@@ -155,11 +156,11 @@ class PpLdapApplication(PpConfigApplication):
                     port = int(ldap_section['port'])
                 except (ValueError, TypeError) as e:
                     msg = "Invalid LDAP port ({s}/port => {v!r}) found in configuration.".format(
-                        s=section, v=ldap_section['port'])
+                        s=section_name, v=ldap_section['port'])
                     raise PpLdapAppError(msg)
                 if port <= 0 or port >= 2 ** 16:
                     msg = "Invalid LDAP port ({s}/port => {v!r}) found in configuration.".format(
-                        s=section, v=port)
+                        s=section_name, v=port)
                     raise PpLdapAppError(msg)
                 self.ldap_port = port
 
@@ -180,7 +181,7 @@ class PpLdapApplication(PpConfigApplication):
                     timeout = int(ldap_section['timeout'])
                 except (ValueError, TypeError) as e:
                     msg = "Invalid LDAP timeout ({s}/port => {v!r}) found in configuration.".format(
-                        s=section, v=ldap_section['timeout'])
+                        s=section_name, v=ldap_section['timeout'])
                     LOG.error(msg)
                 if timeout > 0:
                     self.ldap_timeout = timeout
@@ -236,26 +237,7 @@ class PpLdapApplication(PpConfigApplication):
         MUST be overwritten by descendant classes.
 
         """
-
-        LOG.debug("Executing something ...")
-
-        query_filter = (
-            '(&'
-            '(objectclass=posixAccount)'
-            '(objectclass=shadowAccount)'
-            '(uid=frank.brehm)'
-            ')'
-        )
-
-        entries = self.ldap_search(query_filter)
-
-        print("Found {} LDAP entries.".format(len(entries)))
-        i = 0
-        for entry in entries:
-            i += 1
-            print("\n{}".format(entry))
-            if i >= 5:
-                break
+        LOG.debug("Executing nothing ...")
 
     # -------------------------------------------------------------------------
     def ldap_search(
diff --git a/pp_lib/mk_home_app.py b/pp_lib/mk_home_app.py
new file mode 100644 (file)
index 0000000..f24a6cf
--- /dev/null
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@author: Frank Brehm
+@contact: frank.brehm@pixelpark.com
+@copyright: © 2017 by Frank Brehm, Berlin
+@summary: The module for the mk-home application object.
+"""
+from __future__ import absolute_import
+
+# Standard modules
+import sys
+import os
+import logging
+import logging.config
+import re
+import traceback
+import textwrap
+import copy
+
+# Third party modules
+import six
+
+import ldap3
+
+# Own modules
+from .global_version import __version__ as __global_version__
+
+from .errors import FunctionNotImplementedError, PpAppError
+
+from .common import pp, terminal_can_colors, to_bytes, to_bool
+
+from .merge import merge_structure
+
+from .ldap_app import PpLdapAppError, PpLdapApplication
+
+__version__ = '0.1.2'
+LOG = logging.getLogger(__name__)
+
+
+# =============================================================================
+class PpMkHomeError(PpLdapAppError):
+    pass
+
+
+# =============================================================================
+class PpMkHomeApp(PpLdapApplication):
+    """Class for the 'mk-home' application to ensure:
+        * existence of HOME directories for all users in LDAP
+        * all LDAP users having a valid numeric UID (different to 999999999)
+    """
+
+    default_initial_uid = 999999999
+    default_chroot_homedir = os.sep + os.path.join('mnt', 'nfs', 'home')
+
+    # -------------------------------------------------------------------------
+    def __init__(self, appname=None, version=__version__):
+
+        self.initial_uid = self.default_initial_uid
+        self.chroot_homedir = self.default_chroot_homedir
+        self.simulate = False
+
+        description = textwrap.dedent('''\
+            Home Directory and UIDNumber generation - this script will search for
+            Unix Accounts in LDAP and generate the HomeDirectory for Users if it
+            dosen't exists. Also it looks for accounts with the special
+            UIDNumber {} and generate an new for them.
+            ''').strip().format(self.default_initial_uid)
+
+        super(PpMkHomeApp, self).__init__(
+            appname=appname, version=version, description=description,
+            cfg_stems='mk-home'
+        )
+
+        self.initialized = True
+
+    # -------------------------------------------------------------------------
+    def init_arg_parser(self):
+        """
+        Method to initiate the argument parser.
+
+        This method should be explicitely called by all init_arg_parser()
+        methods in descendant classes.
+        """
+
+        super(PpMkHomeApp, self).init_arg_parser()
+
+        self.arg_parser.add_argument(
+            "-s", "--simulate",
+            action='store_true',
+            dest='simulate',
+            help="Simulation af all actions, nothing is really done."
+        )
+
+    # -------------------------------------------------------------------------
+    def perform_arg_parser(self):
+        """
+        Public available method to execute some actions after parsing
+        the command line parameters.
+
+        Descendant classes may override this method.
+        """
+
+        super(PpMkHomeApp, self).perform_arg_parser()
+
+        if self.args.simulate:
+            self.simulate = True
+
+    # -------------------------------------------------------------------------
+    def perform_config(self):
+
+        super(PpMkHomeApp, self).perform_config()
+
+        for section_name in self.cfg.keys():
+
+            if self.verbose > 2:
+                LOG.debug("Checking config section {!r} ...".format(section_name))
+
+            if section_name.lower() not in ('mk-home', 'mk_home', 'mkhome') :
+                continue
+
+            section = self.cfg[section_name]
+            if self.verbose > 2:
+                LOG.debug("Evaluating config section {n!r}:\n{s}".format(
+                    n=section_name, s=pp(section)))
+
+            if 'initial_uid' in section:
+                v = section['initial_uid']
+                try:
+                    uid = int(v)
+                except (ValueError, TypeError) as e:
+                    msg = (
+                        "Invalid initial numeric user Id ([{s}]/initial_uid "
+                        "=> {v!r}) found in configuration.").format(s=section_name, v=v)
+                    raise PpMkHomeError(msg)
+                if uid <= 0:
+                    msg = (
+                        "Invalid initial numeric user Id ([{s}]/initial_uid "
+                        "=> {v!r}) found in configuration.").format(s=section_name, v=v)
+                    raise PpMkHomeError(msg)
+                self.initial_uid = uid
+
+            if 'chroot_homedir' in section:
+                v = section['chroot_homedir']
+                if not os.path.isabs(v):
+                    msg = (
+                        "The chrooted path of the home directories must be an "
+                        "absolute pathname (found [{s}]/chroot_homedir "
+                        "=> {v!r} in configuration.").format(s=section_name, v=v)
+                    raise PpMkHomeError(msg)
+                self.chroot_homedir = v
+
+    # -------------------------------------------------------------------------
+    def pre_run(self):
+        """
+        Dummy function to run before the main routine.
+        Could be overwritten by descendant classes.
+
+        """
+
+        super(PpMkHomeApp, self).pre_run()
+        if os.geteuid():
+            msg = "Only root may execute this application."
+            LOG.error(msg)
+            self.exit(1)
+
+        if not os.path.exists(self.chroot_homedir):
+            msg = "The chrooted path of the home directories {!r} does not exists.".format(
+                self.chroot_homedir)
+            LOG.error(msg)
+            self.exit(1)
+
+        if not os.path.isdir(self.chroot_homedir):
+            msg = "The chrooted path of the home directories {!r} is not a directory.".format(
+                self.chroot_homedir)
+            LOG.error(msg)
+            self.exit(1)
+
+    # -------------------------------------------------------------------------
+    def _run(self):
+
+        LOG.debug("Executing something ...")
+
+        query_filter = (
+            '(&'
+            '(objectclass=posixAccount)'
+            '(objectclass=shadowAccount)'
+            '(uid=frank.brehm)'
+            ')'
+        )
+
+        entries = self.ldap_search(query_filter)
+
+        print("Found {} LDAP entries.".format(len(entries)))
+        i = 0
+        for entry in entries:
+            i += 1
+            print("\n{}".format(entry))
+            if i >= 5:
+                break
+
+
+# =============================================================================
+
+if __name__ == "__main__":
+
+    pass
+
+# =============================================================================
+
+# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list