]> Frank Brehm's Git Trees - pixelpark/create-vmware-tpl.git/commitdiff
Separating files dependend methods from cr_vmware_tpl.cobbler to cr_vmware_tpl.cobble...
authorFrank Brehm <frank.brehm@pixelpark.com>
Fri, 22 Sep 2023 08:47:33 +0000 (10:47 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Fri, 22 Sep 2023 08:47:33 +0000 (10:47 +0200)
lib/cr_vmware_tpl/cobbler/files.py [new file with mode: 0644]

diff --git a/lib/cr_vmware_tpl/cobbler/files.py b/lib/cr_vmware_tpl/cobbler/files.py
new file mode 100644 (file)
index 0000000..1fac870
--- /dev/null
@@ -0,0 +1,273 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@author: Frank Brehm
+@contact: frank.brehm@pixelpark.com
+@copyright: © 2023 by Frank Brehm, Berlin
+@summary: A mixin module for the Cobbler class for files dependend methods.
+"""
+from __future__ import absolute_import, print_function
+
+# Standard modules
+import logging
+import hashlib
+import textwrap
+
+# Third party modules
+import paramiko
+from paramiko.ssh_exception import SSHException
+
+from fb_tools.common import pp, to_str, is_sequence, to_bool
+from fb_tools.xlate import format_list
+
+# Own modules
+
+from .. import print_section_start, print_section_end
+
+from ..errors import ExpectedCobblerError
+
+from ..xlate import XLATOR
+
+__version__ = '0.1.0'
+
+LOG = logging.getLogger(__name__)
+
+_ = XLATOR.gettext
+ngettext = XLATOR.ngettext
+
+# =============================================================================
+class CobblerFiles():
+    """
+    A mixin class for extending the Cobbler class for files dependend methods.
+    """
+
+    # -------------------------------------------------------------------------
+    def scp_to(self, local_file, remote_file):
+
+        ssh = None
+
+        try:
+
+            if self.verbose > 2:
+                LOG.debug(_("Initializing {} ...").format('paramiko SSHClient'))
+            ssh = paramiko.SSHClient()
+            if self.verbose > 2:
+                LOG.debug(_("Loading SSH system host keys."))
+            ssh.load_system_host_keys()
+            if self.verbose > 2:
+                LOG.debug(_("Setting SSH missing host key policy to {}.").format('AutoAddPolicy'))
+            ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
+
+            if self.verbose > 1:
+                LOG.debug(_("Connecting to {h!r}, port {p} as {u!r} per SSH ...").format(
+                    h=self.host, p=self.ssh_port, u=self.ssh_user))
+
+            if self.simulate:
+                LOG.debug(_(
+                    "Simulating SCP of {local!r} to {user}@{host}:{remote} ...").format(
+                    local=str(local_file), user=self.ssh_user,
+                    host=self.host, remote=str(remote_file)))
+
+            else:
+                ssh.connect(
+                    self.host, port=self.ssh_port, timeout=self.ssh_timeout,
+                    username=self.ssh_user, key_filename=self.private_ssh_key)
+
+                sftp = ssh.open_sftp()
+
+                LOG.debug(_("SCP of {local!r} to {user}@{host}:{remote} ...").format(
+                    local=str(local_file), user=self.ssh_user,
+                    host=self.host, remote=str(remote_file)))
+
+                sftp.put(str(local_file), str(remote_file))
+
+        except SSHException as e:
+            msg = _("Could not connect via {w} to {user}@{host}: {e}").format(
+                w='SCP', user=self.ssh_user, host=self.host, e=e)
+            raise ExpectedCobblerError(msg)
+
+        finally:
+            sftp = None
+            if ssh:
+                if self.verbose > 2:
+                    LOG.debug(_("Closing SSH connection."))
+                ssh.close()
+
+    # -------------------------------------------------------------------------
+    def check_remote_directory(self, rdir, desc=None):
+
+        if self.verbose > 1:
+            msg = _("Checking existence of remote directory {!r} ...").format(str(rdir))
+            LOG.debug(msg)
+
+        cmd = textwrap.dedent("""\
+        if [ -d {rdir!r} ] ; then
+            exit 0
+        fi
+        exit 7
+        """).format(rdir=str(rdir))
+
+        proc = self.exec_ssh(cmd)
+        if proc.returncode != 0:
+            dsc = _('Remote directory')
+            if desc:
+                dsc = desc
+            msg = _(
+                "{dsc} {rdir!r} on host {host!r} does not exists or is not a directory.").format(
+                    dsc=dsc, rdir=str(rdir), host=self.host)
+            raise ExpectedCobblerError(msg)
+
+    # -------------------------------------------------------------------------
+    def ensure_remote_directory(self, rdir, desc=None):
+
+        if self.verbose:
+            msg = _("Ensuring existence of remote directory {!r} ...").format(str(rdir))
+            LOG.debug(msg)
+
+        verb = ''
+        if self.verbose:
+            verb = " --verbose"
+
+        cmd = textwrap.dedent("""\
+        if [ -d {rdir!r} ] ; then
+            exit 0
+        fi
+        if [ -e {rdir!r} ] ; then
+            echo "Path {rdir!r} exists, but is not a directory." >&2
+            exit 7
+        fi
+        mkdir --parents{verb} {rdir!r}
+        """).format(rdir=str(rdir), verb=verb)
+
+        proc = self.exec_ssh(cmd)
+        if proc.returncode == 0:
+            if proc.stdout:
+                LOG.debug(_("Output:") + "\n{}".format(proc.stdout))
+        else:
+            dsc = _('Remote directory')
+            if desc:
+                dsc = desc
+            err = _('No error message')
+            if proc.stderr:
+                err = proc.stderr
+            elif proc.stdout:
+                err = proc.stdout
+            msg = _(
+                "{dsc} {rdir!r} on host {host!r} could not be created: {err}").format(
+                dsc=dsc, rdir=str(rdir), host=self.host, err=err)
+            raise ExpectedCobblerError(msg)
+
+    # -------------------------------------------------------------------------
+    def ensure_remote_file(self, local_file, remote_file, check_parent=True):
+
+        if check_parent:
+            self.check_remote_directory(remote_file.parent)
+
+        msg = _("Checking remote file {rfile!r} based on local {lfile!r} ...").format(
+            rfile=str(remote_file), lfile=str(local_file))
+        LOG.debug(msg)
+
+        if not local_file.exists() or not local_file.is_file():
+            msg = _("Local file {!r} either not exists or is not a regular file.").format(
+                str(local_file))
+            raise ExpectedCobblerError(msg)
+        local_file_content = local_file.read_bytes()
+        digest = hashlib.sha256(local_file_content).hexdigest()
+        if self.verbose > 1:
+            LOG.debug(_('{typ} sum of {ks!r} is: {dig}').format(
+                typ='SHA256', ks=str(local_file), dig=digest))
+
+        cmd = textwrap.dedent("""\
+        if [ -f {rfile!r} ] ; then
+            digest=$(sha256sum {rfile!r} | awk '{{print $1}}')
+            echo "Digest: ${{digest}}"
+            if [ "${{digest}}" != {dig!r} ] ; then
+                echo "SHA256 sum does not match." >&2
+                exit 4
+            fi
+            exit 0
+        else
+            exit 3
+        fi
+        """).format(rfile=str(remote_file), dig=digest)
+
+        proc = self.exec_ssh(cmd)
+        if proc.returncode == 0:
+            LOG.debug(_("Remote file {!r} has the correct content.").format(
+                str(remote_file)))
+            return
+
+        msg = _("File {!r} has to be copied.").format(str(local_file))
+        LOG.warn(msg)
+
+        self.scp_to(local_file, remote_file)
+
+    # -------------------------------------------------------------------------
+    def get_remote_filecontent(self, remote_file):
+
+        LOG.debug(_("Getting content of remote file {!r} ...").format(str(remote_file)))
+
+        cmd = textwrap.dedent("""\
+        if [ -f {rfile!r} ] ; then
+            cat {rfile!r}
+        else
+            echo "Remote file does not exists." >&2
+            exit 7
+        fi
+        """).format(rfile=str(remote_file))
+
+        proc = self.exec_ssh(cmd)
+        if proc.returncode:
+            err = _('No error message')
+            if proc.stderr:
+                err = proc.stderr
+            elif proc.stdout:
+                err = proc.stdout
+            msg = _(
+                "Error getting content of {rfile!r} on host {host!r} - "
+                "returncode was {rc}: {err}").format(
+                rfile=str(remote_file), host=self.host, rc=proc.returncode, err=err)
+            raise ExpectedCobblerError(msg)
+
+        return proc.stdout
+
+    # -------------------------------------------------------------------------
+    def ensure_root_authkeys(self, tmp_auth_keys_file=None):
+
+        bname = 'auth_keys_pp_betrieb'
+        if tmp_auth_keys_file:
+            local_file = tmp_auth_keys_file
+        else:
+            local_file = self.base_dir / 'keys' / bname
+        remote_file = self.cfg.cobbler_ws_docroot / self.cfg.cobbler_ws_rel_filesdir / bname
+
+        self.ensure_remote_file(local_file, remote_file)
+
+    # -------------------------------------------------------------------------
+    def ensure_rsyslog_cfg_files(self):
+
+        files_dir = self.base_dir / 'files'
+        docroot = self.cfg.cobbler_ws_docroot / self.cfg.cobbler_ws_rel_filesdir
+        remote_dir = docroot / self.cfg.system_status
+
+        LOG.info(_("Ensuring currentness of rsyslog config files ..."))
+        print_section_start(
+            'ensure_rsyslog_cfg_files', 'Ensuring rsyslog config files.', collapsed=True)
+
+        for local_cfg_file in files_dir.glob('*rsyslog.conf*'):
+            remote_cfg_file = remote_dir / local_cfg_file.name
+            LOG.debug(_("Ensuring {loc!r} => {rem!r}.").format(
+                loc=str(local_cfg_file), rem=str(remote_cfg_file)))
+            self.ensure_remote_file(local_cfg_file, remote_cfg_file, check_parent=False)
+
+        print_section_end('ensure_rsyslog_cfg_files')
+
+
+# =============================================================================
+if __name__ == "__main__":
+
+    pass
+
+# =============================================================================
+
+# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list