Mini Shell

Direktori : /opt/sharedrads/python/send_customer_str/
Upload File :
Current File : //opt/sharedrads/python/send_customer_str/check_dcpumon

#!/opt/imh-python/bin/python3
"""Displays dcpumon info for one user as an HTML table"""
import argparse
import subprocess
import os
import re
import time
import pty
import errno
import select
from prettytable import PrettyTable
import rads


def parse_args():
    """Parse sys.argv"""
    parser = argparse.ArgumentParser(description=__doc__)
    # --user is only for backwards compat
    parser.add_argument(
        '-u', '--user', action='store_true', dest='u', help=argparse.SUPPRESS
    )
    parser.add_argument('user', help='cPanel username')
    args = parser.parse_args()
    if not rads.is_cpuser(args.user):
        print(rads.color.red(f"Not a valid cPanel user: {args.user}"))
    return args.user


def dcpumon() -> str:
    """Run dcpumonview {24h ago} {now} and return stdout as a str"""
    # master_fd, slave_fd = pty.openpty()
    start = str(int(time.time()) - 86400)  # 24h ago
    stop = str(int(time.time()))  # now
    cmd = ['/usr/local/cpanel/bin/dcpumonview', start, stop]
    # dcpumonview prints HTML if it thinks it's not attached to a TTY
    stdout = tty_capture(cmd)
    return str(stdout, 'utf-8', 'ignore')


def tty_capture(cmd: list[str]) -> bytes:
    """Run a subprocess with PTYs attached"""
    # https://stackoverflow.com/a/52954716
    # https://stackoverflow.com/a/70166246
    m_out, s_out = pty.openpty()
    m_err, s_err = pty.openpty()
    m_in, s_in = pty.openpty()
    with subprocess.Popen(
        cmd,
        bufsize=1,
        stdin=s_in,
        stdout=s_out,
        stderr=s_err,
        close_fds=True,
        env={"LINES": "40", "COLUMNS": "200", "TERM": "xterm-256color"},
    ) as proc:
        for ready_fd in [s_out, s_err, s_in]:
            os.close(ready_fd)
        timeout = 0.04
        readable = [m_out, m_err]
        result = {m_out: b'', m_err: b''}
        try:
            while readable:
                ready, _, _ = select.select(readable, [], [], timeout)
                for ready_fd in ready:
                    try:
                        data = os.read(ready_fd, 512)
                    except OSError as e:
                        if e.errno != errno.EIO:
                            raise
                        readable.remove(ready_fd)
                    else:
                        if not data:  # EOF
                            readable.remove(ready_fd)
                        result[ready_fd] += data
        finally:
            for ready_fd in [m_out, m_err, m_in]:
                os.close(ready_fd)
            if proc.poll() is None:
                proc.kill()
            proc.wait()
    # stderr is result[m_err], but we don't use that in this script
    return result[m_out]


def check_dcpumon(user: str):
    """Filter dcpumon output for one user and output as an html table"""
    hitfound = False
    tbl_data = False
    tbl = PrettyTable([f"Top Process for {user}"])
    tbl.align[f"Top Process for {user}"] = 'l'
    user_re = re.compile(r'\|' + re.escape(user) + r'[_\s]*\|')
    # |userna5_|example.com        |0.00|0.00|0.0   |
    # | Top Process | 0.1 | dovecot/imap |
    # |userna6 |example2.com       |0.00|0.00|0.0   |
    for line in dcpumon().splitlines():
        if user_re.match(line):
            hitfound = True
            continue
        if not hitfound:
            continue
        if line.startswith('| Top'):
            cmd = line.strip(' |').split('|')[-1].strip(' |')
            tbl_data = True
            tbl.add_row([cmd])
        else:
            hitfound = False
    if tbl_data:
        print(tbl.get_html_string(attributes={"class": "proc_body"}))


def main():
    """Displays dcpumon info for one user as an HTML table"""
    user = parse_args()
    check_dcpumon(user)


if __name__ == "__main__":
    main()

Zerion Mini Shell 1.0