Mini Shell

Direktori : /opt/sharedrads/
Upload File :
Current File : //opt/sharedrads/packandgo

#!/opt/imh-python/bin/python3
"""Pack and Go"""
from os import cpu_count
import random
import string
from pathlib import Path
from cproc import Proc
import subprocess
import sys
import argparse
import arrow
import platform
import rads

MAX_GB = 20


def parse_args() -> str:
    """Get the one argument, the user"""
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('user', help='Username')
    args = parser.parse_args()
    if rads.is_cpuser(args.user):
        return args.user
    sys.exit('ERROR: Not a user.')


def check_size(username: str) -> None:
    """If over 20GB, not packaging. They will need to use FTP.
    Gets user disk usage using the quotactl syscall"""
    quotactl = rads.QuotaCtl()
    try:
        size_bytes = quotactl.getquota(username)
    except rads.QuotasDisabled:
        sys.exit("Filesystem quotas are disabled; Try /scripts/fixquotas")
    except Exception as exc:
        sys.exit(f"{type(exc).__name__}: {exc}")
    if size_bytes < 2**30:  # < 1 GiB
        print(f"{username}'s size: {round(size_bytes / 2**20, 2)} MiB")
    else:
        print(f"{username}'s size: {round(size_bytes / 2**30, 2)} GiB")
    if size_bytes > MAX_GB * 2**30:
        sys.exit(f"Over {MAX_GB}GiB - user will need to collect data via FTP")


def pack_it_up(username: str) -> Path:
    """cpuwatched pkgacct"""
    cmd = ['/usr/local/cpanel/scripts/pkgacct', username]
    print(f"Packing up {username}. This may take a while...")
    try:
        ret = Proc.run(
            cmd,
            lim=cpu_count(),
            stdout=Proc.PIPE,
            stderr=Proc.STDOUT,
            encoding='utf-8',
            check=True,
        )
    except Proc.CalledProcessError as exc:
        if exc.returncode < 0:
            sys.exit(
                'Failed to create package - pkgacct process was killed '
                f'(signal {-exc.returncode})'
            )
        sys.exit(f'{exc.stdout}\n\nFailed to create package')
    path = None
    for line in ret.stdout.splitlines():
        line: str
        if 'pkgacctfile is:' in line:
            path = Path(line.split(' ')[-1].strip('\n'))
    if path is None:
        sys.exit(
            f"{ret.stdout}\n\nFailed to create package - "
            'pkgacct returned a successful exit code, but it did not '
            'print the expected output, "pkgacctfile is: <path>"'
        )
    if not path.is_file():
        sys.exit(f"Backup file not found at: {path}")
    return path


def file_precheck(username: str) -> None:
    """Checks if backup already exists"""
    path = Path(f'/home/cpmove-{username}.tar.gz')
    if path.exists():
        sys.exit(
            f"ERROR: {path} already exists. Please remove for fresh backup"
        )


def sec_dir() -> Path:
    if rads.SECURE_USER is None:
        sys.exit("Could not identify secure user name.")
    rand = ''.join(random.choices(string.ascii_letters + string.digits, k=48))
    path = Path('/home', rads.SECURE_USER, 'public_html', rand)
    path.mkdir(mode=0o755, parents=True, exist_ok=False)
    return path


def move_it(pkgacct_file: Path, dest_dir: Path) -> Path:
    """Moves newly created backup to secure users dir"""
    pkgacct_file.rename(dest_dir / pkgacct_file.name)
    rcode = subprocess.call(
        ['/usr/bin/fixperms', rads.SECURE_USER],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )
    if rcode:
        print(f"Warning: fixperms exited {rcode}")


def send_recl_email(sec_dir_path: Path) -> None:
    """Sends e-mail to reclamations to delete in 3 days"""
    time_now = arrow.now().shift(days=3)
    recl_date = time_now.format('MM-DD-YYYY')
    hostname = platform.node()
    to_addy = "reclamations@imhadmin.net"
    subject = f"{hostname} : Reclaim cpmove {recl_date}"
    body = f"{hostname} : rm -rvf {sec_dir_path}"
    if rads.send_email(to_addy, subject, body) is False:
        print("Reclamation request for removal in 72 hours of backup, sent.")
    else:
        print("Sending of reclamation request failed. Please send manually.")


def main():
    """Main function to pack and go"""
    user = parse_args()
    file_precheck(user)
    check_size(user)
    sec_dir_path = sec_dir()
    bak_homepath = pack_it_up(user)
    move_it(bak_homepath, sec_dir_path)
    print(
        "Download Link:",
        f"https://{rads.SECURE_FQDN}/{sec_dir_path.name}/{bak_homepath.name}",
    )
    send_recl_email(sec_dir_path)


if __name__ == '__main__':
    main()

Zerion Mini Shell 1.0