Mini Shell

Direktori : /usr/share/l.v.e-manager/utils/
Upload File :
Current File : //usr/share/l.v.e-manager/utils/autorestore.py

#!/opt/cloudlinux/venv/bin/python3 -sbb
# coding:utf-8

# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT

# for details see LVEMAN-622: Create autorestore quota limits after 1.0-9.9 update

from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future.utils import iteritems
import glob
import gzip
import os
import sys
import shutil
import subprocess
import time


UPDATE_USER = "/scripts/modcpuser"
UPDATE_QUOTA = "/scripts/editquota"

QUOTA_CONF = "/etc/quota.conf"
USERS_DIR = "/var/cpanel/users"
PACKAGES_DIR = "/var/cpanel/packages"

PLAN_KEYS = ["HASCGI", "HASDKIM", "HASSPF", "QUOTA", "BWLIMIT", "MAXPOP",
             "MAXFTP", "MAXLST", "MAXSQL", "MAXSUB", "MAXPARK", "MAXADDON",
             "MAX_EMAIL_PER_HOUR", "MAX_DEFER_FAIL_PERCENTAGE"]


class Main(object):
    """
    """
    _cached_quota = {}
    _cached_users = {}
    _cached_packages = {}
    _packages = {}
    _users = {}

    def __init__(self, backup_varcpanel, backup_etcquota):
        """
        Constructor
        """
        self._backup_etcquota = backup_etcquota
        self._backup_varcpanel = backup_varcpanel
        self._load_quota_cache()

    def run(self):
        """
        Run main action
        """
        # load packages data
        self._load_packages()

        # load users conf
        self._load_users()
        self._load_users_quota()

        # load varcpanel cache for all users
        self._load_varcpanel_cache()

        # create backup user configs before restore
        self._backup_users()

        # check users differs
        self._check_users()

    def _load_quota_cache(self):
        """
        Load cached quota settings
        """
        # load backup files
        f = gzip.open(self._backup_etcquota, "rb")
        for line in f:
            line = line.strip()

            if not line:
                continue

            user, value = line.split("=")
            self._cached_quota[user.strip()] = value.strip()
        f.close()

    def _load_varcpanel_cache(self):
        """
        Load cache for users and packages
        """
        cmd = ["/bin/tar -C /tmp -xf %s %s %s" % (self._backup_varcpanel,
            USERS_DIR.lstrip("/"), PACKAGES_DIR.lstrip("/"))]
        p = subprocess.Popen(cmd, shell=True, executable='/bin/bash',
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        out, err = p.communicate()
        if err:
            print(err)
            sys.exit(0)

        # load users cache
        users_cache_dir = "/tmp%s" % USERS_DIR
        for cache_path in glob.glob("%s/*" % users_cache_dir):
            data = self._read_file(cache_path)
            username = cache_path.split("/")[-1]
            self._cached_users[username] = data

        # load packages cache
        packages_cache_dir = "/tmp%s" % PACKAGES_DIR
        for cache_path in glob.glob("%s/*" % packages_cache_dir):
            if not os.path.isfile(cache_path):
                # skip extensions directory
                continue

            data = self._read_file(cache_path)
            if "CGI" in data:
                data["CGI"] = {"y": "1", "n": "0"}.get(data["CGI"], data["CGI"])

            username = cache_path.split("/")[-1]
            self._cached_packages[username] = data

        shutil.rmtree(users_cache_dir)
        shutil.rmtree(packages_cache_dir)

    def _load_packages(self):
        """
        Load current packages configures
        """
        for package_path in glob.glob("%s/*" % PACKAGES_DIR):
            if not os.path.isfile(package_path):
                continue

            pack = self._read_file(package_path)
            if "CGI" in pack:
                pack["CGI"] = {"y": "1", "n": "0"}.get(pack["CGI"], pack["CGI"])

            self._packages[package_path.split("/")[-1]] = pack

    def _load_users(self):
        """
        Load current users settings
        """
        for user_path in glob.glob("%s/*" % USERS_DIR):
            if not os.path.isfile(user_path):
                continue

            user = self._read_file(user_path)
            self._users[user_path.split("/")[-1]] = user

    def _load_users_quota(self):
        """
        Load config file with all users quotas
        """
        quota = self._read_file(QUOTA_CONF)
        for user, value in iteritems(quota):
            if user in self._users:
                self._users[user]["QUOTA"] = value

    def _check_users(self):
        """
        Check users settings
        """
        for username, conf in iteritems(self._users):
            if not self._is_need_restore_settings(username, conf):
                # skip if different values
                continue

            # restore only users with package values
            print("Restore %s" % username)

            # reset to backup quota settings
            if username in self._cached_quota \
                    and conf["QUOTA"] != self._cached_quota[username]:
                # reset quota config
                params = [UPDATE_QUOTA, username, "%sM" % self._cached_quota[username]]
                p = subprocess.Popen(params, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                # print params
                out, err = p.communicate()
                if err:
                    print("UPDATE_QUOTA error:")
                    print(err)

            # skip users without cache
            if username not in self._cached_users:
                print("    %s has not cached data - skip" % username)
                continue

            # skip users with plan differ from cached
            if self._cached_users[username]["PLAN"] != conf["PLAN"]:
                print("    %s changed plan from '%s' to '%s' - skip" % \
                    (username, self._cached_users[username]["PLAN"], conf["PLAN"]))
                continue

            # reset to backup limits settings
            for key in PLAN_KEYS:
                if key in self._cached_users[username] \
                        and conf[key] != self._cached_users[username][key]:

                    # check difference between old package value and current package value
                    if conf["PLAN"] in self._cached_packages and conf["PLAN"] in self._packages \
                        and self._cached_packages[conf["PLAN"]].get(key) \
                            != self._packages[conf["PLAN"]].get(key):
                        print("Package value '%s' was changed - skip" % key)
                        continue

                    params = [UPDATE_USER, "--user", username, "--action", "set",
                              "--key", key, "--value", self._cached_users[username][key]]

                    p = subprocess.Popen(params, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                    # print params
                    out, err = p.communicate()
                    if err:
                        print("UPDATE_USER error:")
                        print(err)

    def _backup_users(self):
        """
        Backup users configs files before restore
        """
        ts = time.time()
        # backup users directory
        backup_dir = "%s.%s" % (USERS_DIR, ts)
        shutil.copytree(USERS_DIR, backup_dir)
        # backup quota.conf file
        backup_file = "%s.%s" % (QUOTA_CONF, ts)
        shutil.copy2(QUOTA_CONF, backup_file)

    def _is_need_restore_settings(self, username, conf):
        """
        Compare plan settings and users config
        :return: bool. if true - need restore data, false - no
        """
        if "default" == conf["PLAN"]:
            # default plan has no settings, but has user personal settings
            return True

        if conf["PLAN"] not in self._packages:
            # if user current plan no in packages - skip it
            print("    %s plan no in current packages - skip" % username)
            return False

        COMPARE_KEYS = {"CGI": "HASCGI"}
        for key, value in iteritems(self._packages[conf["PLAN"]]):
            if key not in ["CGI", "DIGESTAUTH", "HASSHELL"] + PLAN_KEYS:
                continue

            conf_key = COMPARE_KEYS.get(key, key)
            if conf_key in conf and conf[conf_key] != value:
                return False

        return True

    def _read_file(self, filename):
        """
        helper util
        """
        result = {}
        u = open(filename, "r")
        for line in u:
            line = line.strip()
            if not line or line.startswith("#"):
                continue

            key, value = line.split("=")
            result[key.strip()] = value.strip()

        u.close()
        return result


if "__main__" == __name__:
    if len(sys.argv[1:]) < 2:
        print("%s <backup_varcpanel> <backup_etcquota>" % sys.argv[0])
        sys.exit(1)

    Main(*sys.argv[1:]).run()

#./autorestore.py /backup/cpbackup/weekly/dirs/_var_cpanel.tar.gz /backup/cpbackup/weekly/files/_etc_quota.conf.gz
#./autorestore.py /tmp/var.tgz /backup/cpbackup/weekly/files/_etc_quota.conf.gz

Zerion Mini Shell 1.0