ok

Mini Shell

Direktori : /opt/alt/python37/lib/python3.7/site-packages/clcommon/public_hooks/bundle/directadmin/
Upload File :
Current File : //opt/alt/python37/lib/python3.7/site-packages/clcommon/public_hooks/bundle/directadmin/manager.py

# -*- coding: utf-8 -*-

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2018 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
#
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import os
import pwd
import subprocess
from collections import namedtuple

import shutil

import logging

from clcommon.utils import get_file_lines, write_file_lines, mod_makedirs
from clcommon.public_hooks import CLOUDLINUX_HOOKS, CONTACT_SUPPORT_MESSAGE_FOOTER
from clcommon.cpapi import get_cp_description
from distutils.version import StrictVersion
BIN_DIR = os.path.join(CLOUDLINUX_HOOKS, 'directadmin/')


Hook = namedtuple('Hook', ['path', 'hook'])
HookPath = namedtuple('HookPath', ['min_version', 'max_version', 'path'])

HOOKS = { # None means +inf or -int depending on positions
    Hook(BIN_DIR + 'user_create_post', (HookPath(None, '1.60', 'user_create_post.sh'),
                                        HookPath('1.60', None, 'user_create_post/CL_user_create_post.sh'))),
    Hook(BIN_DIR + 'user_destroy_post', (HookPath(None, '1.60', 'user_destroy_post.sh'),
                                         HookPath('1.60', None, 'user_destroy_post/CL_user_destroy_post.sh'))),
    Hook(BIN_DIR + 'user_destroy_pre', (HookPath(None, '1.60', 'user_destroy_pre.sh'),
                                        HookPath('1.60', None, 'user_destroy_pre/CL_user_destroy_pre.sh'))),
    Hook(BIN_DIR + 'user_restore_post', (HookPath(None, '1.60', 'user_restore_post.sh'),
                                         HookPath('1.60', None, 'user_restore_post/CL_user_restore_post.sh'))),
    Hook(BIN_DIR + 'domain_change_post', (HookPath(None, '1.60', 'domain_change_post.sh'),
                                          HookPath('1.60', None, 'domain_change_post/CL_domain_change_post.sh'))),
}
DA_HOOK_DEST_DIR = '/usr/local/directadmin/scripts/custom'
if get_cp_description() is None:
    DA_VERSION = '1.0'  # in case we can't determine version we set default old
else:
    DA_VERSION = get_cp_description()["version"]

logger = logging.getLogger(__name__)


def _folder_hooks_compatibility():
    """
    Check that DA has compatibility with folder-based hooks
    :return: Bool
    """
    return StrictVersion(DA_VERSION) >= StrictVersion('1.60')


def _get_hook_from_structure(hook):
    """
    hook = HookPath stucture
    return suitable hook name depending on version
    if return None - suitable hook not found
    """
    for version_hook in hook:
        if version_hook.min_version is None:
            min_version = True
        else: # if DA bigger than the min val
            min_version = StrictVersion(DA_VERSION) >= StrictVersion(version_hook.min_version)
        if version_hook.max_version is None:
            max_version = True
        else: # if DA lesser that the max val
            max_version = StrictVersion(DA_VERSION) < StrictVersion(version_hook.max_version)
        if min_version and max_version:
            return version_hook.path
    return None


def create_da_hook(da_hook_filename, command, da_hook_default_dir=DA_HOOK_DEST_DIR):
    """
    Creates DA hook
    Example args:
    da_hook_filename = user_create_post.sh
    da_hook_src = /usr/share/cagefs-plugins/hooks/directadmin/user_create_post.sh - command

    :param string da_hook_filename: How to name that hook in DA panel
    :param command: what we should run on hook
    :param string da_hook_default_dir:
    :return: None
    """

    hook_fullname = os.path.join(da_hook_default_dir, da_hook_filename)

    logger.debug('Registering %s action hook', hook_fullname)
    try:
        da_user = pwd.getpwnam('diradmin')
    except (KeyError,) as e:
        logger.error("failed to find 'diradmin' user: %s", str(e))
        return

    da_user_uid = da_user.pw_uid
    da_user_gid = da_user.pw_gid

    try:
        # if hook file already in system
        if os.path.isfile(hook_fullname):
            # get hook content
            content = get_file_lines(hook_fullname)
            content = [line for line in content if line != '\n']
            # Flags for check if hook installed and if hook on bash
            hook_installed = False
            hook_on_bash = False

            for line in content:
                # check if hook installed
                if line.find(command) != -1:
                    hook_installed = True
                    break
                # check if hook on bash
                if line.startswith('#!/') and (line.find('/sh') != -1 or line.find('/bash') != -1):
                    hook_on_bash = True

            # if hook not installed
            if not hook_installed:
                # if hook on bash
                if hook_on_bash:
                    # add command for cagefs hook
                    content.append('\n' + command + '\n')
                    write_file_lines(hook_fullname, content, 'w')
                else:  # if hook not on bash
                    try:
                        # backup old hook filename
                        dirname, fname = os.path.split(hook_fullname)
                        old_hook_backup = os.path.join(dirname, 'old_'+fname)

                        # copy backup old hook
                        shutil.copyfile(hook_fullname, old_hook_backup)
                        os.chmod(old_hook_backup, 0o700)
                        os.chown(old_hook_backup, da_user_uid, da_user_gid)

                        # replace old hook by new hook on bash
                        write_file_lines(hook_fullname,
                                         '#!/bin/bash\n' + command + '\n' + old_hook_backup + '\n', 'w')
                        os.chmod(hook_fullname, 0o700)
                        os.chown(hook_fullname, da_user_uid, da_user_gid)
                    except (OSError, shutil.Error) as e:
                        logger.error('Failed to create hook for DirectAdmin: %s: %s. %s',
                                     hook_fullname, str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)
    except (OSError, IOError) as e:
        logger.error('Failed to install hook for DirectAdmin: %s. %s',
                     str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)

    # Install hook if it's not installed
    if not os.path.isfile(hook_fullname):
        try:
            if not os.path.isdir(os.path.dirname(hook_fullname)):
                mod_makedirs(os.path.dirname(hook_fullname), 0o700)
                os.chmod(os.path.dirname(hook_fullname), 0o700)
                os.chown(os.path.dirname(hook_fullname), da_user_uid, da_user_gid)
            write_file_lines(hook_fullname, '#!/bin/bash\n' + command + '\n', 'w')
            os.chmod(hook_fullname, 0o700)
            os.chown(hook_fullname, da_user_uid, da_user_gid)
        except (OSError, IOError) as e:
            logger.error('Failed to install hook for DirectAdmin: %s. %s',
                         str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)


# DO NOT CHANGE THIS METHOD
# STILL USED IN LVEMANAGER & CAGEFS
def remove_da_hook(da_hook_filename, command, da_hook_default_dir=DA_HOOK_DEST_DIR):
    """
    Removes DA hook
    da_hook_default_dir = DA_HOOK_DEST_DIR = /usr/local/directadmin/scripts/custom
    da_hook_filename = user_create_post.sh
    command = /usr/share/cagefs-plugins/hooks/directadmin/user_create_post.sh

    :param string da_hook_filename: How to name that hook in DA panel
    :param command: what we should run on hook
    :param da_hook_default_dir: default dir for hooks
    :return: None
    """
    logger.debug('Unregistering %s action hook', da_hook_filename)

    hook_fullname = os.path.join(da_hook_default_dir, da_hook_filename)

    # check if hook exist in system
    if not os.path.isfile(hook_fullname):
        logger.info('Hook %s is not installed; skip', hook_fullname)
        return

    try:
        content = get_file_lines(hook_fullname)
        new_content = []
        for line in content:
            # check for hook execution command in hook
            if line != '\n' and line.find(command) == -1:
                new_content.append(line)
        # write changes to hook
        write_file_lines(hook_fullname, new_content, 'w')
    except IOError as e:
        logger.error('Failed to remove hook for DirectAdmin: %s. %s',
                     str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)


def install_hooks():
    if not _folder_hooks_compatibility():
        subprocess.run("touch {}/.old_hooks_present".format(DA_HOOK_DEST_DIR), shell=True, executable='/bin/bash')
    else:
        if os.path.isfile("{}/.old_hooks_present".format(DA_HOOK_DEST_DIR)):
            remove_hooks()

    for hook_structure in HOOKS:
        hook_name = _get_hook_from_structure(hook_structure.hook)
        if hook_name is None:
            logger.error('Failed to install hook for DirectAdmin: %s. %s',
                         "Can't find suitable version", CONTACT_SUPPORT_MESSAGE_FOOTER)
            continue
        create_da_hook(hook_name, hook_structure.path)


def remove_hooks():
    if _folder_hooks_compatibility and os.path.isfile("{}/.old_hooks_present".format(DA_HOOK_DEST_DIR)):
        subprocess.run("rm -f {}/.old_hooks_present".format(DA_HOOK_DEST_DIR), shell=True, executable='/bin/bash')
    for hook_structure in HOOKS:
        hook_names = [version_hook.path for version_hook in hook_structure.hook]
        for name in hook_names:
            remove_da_hook(name, hook_structure.path)

Zerion Mini Shell 1.0