PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /opt/sharedrads/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //opt/sharedrads/check_lve |
#!/opt/imh-python/bin/python3 """Generate a chart of resource usage as reported by lveinfo. This script can also generate a resource usage chart for user review.""" from rads import prompt_y_n, is_cpuser from rads.color import red, green from collections import OrderedDict from prettytable import PrettyTable from pwd import getpwuid, getpwnam from grp import getgrnam import subprocess import argparse import json import sys import os USERCOUNT = 15 def parse_args(): """Get command line arguments""" parser = argparse.ArgumentParser(description=__doc__) # fmt: off group = parser.add_mutually_exclusive_group(required=True) # mutually exclusive arguments group.add_argument( "-c", "--cpu", action="store_true", dest="CPU", help="Show and sort by CPU usage", ) group.add_argument( "-m", "--memory", action="store_true", dest="Mem", help="Show and sort by memory (physical and virtual) usage", ) group.add_argument( "-p", "--procs", action="store_true", dest="Proc", help="Show and sort by processes", ) group.add_argument( "-i", "--io", action="store_true", dest="IO", help="Show and sort by IO and IO Operations", ) group.add_argument( "-f", "--faults", action="store_true", dest="Fault", help="Show and sort by cpu, proc, mem, and IO faults.", ) group.add_argument( "--chart", action="store_true", dest="Chart", help="Generate a chart for the given user in --location", ) # additional arguments (location and user) parser.add_argument( "-l", "--location", action="store", dest="Location", nargs="?", help="Designate the location for the chart image generated " "e.g. /home/userna5/lvechart.9-30.png", ) parser.add_argument( "-u", "--user", action="store", dest="User", nargs="?", help="User for chart generation", ) parser.add_argument( "-t", "--time", action="store", dest="Time", nargs="?", default="5m", help="time period; specify minutes (m), hours (h), days (d), today, " "yesterday; 5m - last 5 minutes, 4h - last four hours, 2d - last " "2 days including today", ) # fmt: on # get the args results = parser.parse_args() # if a location is provided, we probably meant to --chart if results.Location and not results.Chart: print("Assuming --chart") results.Chart = True # if --chart but no --user or --location if results.Chart and (not results.User or not results.Location): print(red("--chart requires a user and a location.")) sys.exit(1) # check to make sure User is an actual cPanel user if results.User and not is_cpuser(results.User): print(red(f"{results.User} is not a valid cPanel user.")) sys.exit(1) # make sure the path to --location exists if results.Location and not os.path.exists( os.path.dirname(results.Location) ): print( red(os.path.dirname(results.Location)), red("is not a valid path. Does it exist?"), ) sys.exit(1) # get the owner of the --location dir if results.Location: owner = getpwuid( os.stat(os.path.dirname(results.Location)).st_uid ).pw_name # is the --location owned by --user? If not, verify this is okay if results.User and results.User != owner: # The user and location owner don't match. Prompt to continue if not prompt_y_n( f"{owner} is the owner of {results.Location} but you entered " f"--user {results.User}. Proceed?" ): print("Exiting.") sys.exit(1) return results def generate_chart(user, location): """Generate the LVE chart in the provided location lvechart --period=5d --user=$USER --output=$LOCATION""" userarg = f"--user={user}" locationarg = f"--output={location}" try: # run lvechart --period=5d --user=$user --output=$location subprocess.call(["lvechart", "--period=5d", userarg, locationarg]) os.chown(location, getpwnam(user).pw_uid, getgrnam(user).gr_gid) print(green(f"Chart successfully generated for {user} at {location}")) except subprocess.CalledProcessError as error: print(red(error.output)) def lveinfo(sortmethod, time, columns): """Run lve info with the provided arguments lveinfo -d --period=5m -o $sort --show-columns $columns""" try: # fmt: off data = subprocess.check_output([ "lveinfo", "-d", f"--period={time}", "--json", "-o", sortmethod, "--show-columns", columns, ]) # fmt: on return data except subprocess.CalledProcessError as error: print(red(error.output)) sys.exit(1) def tableify(table, data): """Format given data into a pretty table""" for row in data: table.add_row([key[1] for key in row.items()]) print(table) def sizeof_fmt(num, suffix='B'): for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: if abs(num) < 1024.0: return f"{num:3.1f}{unit}{suffix}" num /= 1024.0 return "{:.1f}{}{}".format(num, 'Yi', suffix) def main(): """Main program logic. Build the arguments for lveinfo, collect the json output, rearrange and reformat as needed, and send to prettytable for actual output.""" table = PrettyTable() args = parse_args() data = None if args.Chart: # skip everything else, we're making a chart for the user generate_chart(args.User, args.Location) # collect the json of the desired resource check elif args.CPU: print(f"Printing {args.Time} CPU usage statistics...") resources = ["ID", "uCPU", "lCPU", "CPUf"] sortmethod = "aCPU" table.field_names = [ "User", "AVG used", "Core Limit", "Limit Reached #", ] elif args.Mem: print(f"Printing {args.Time} Memory usage statistics...") resources = ["ID", "aPMem", "lPMem", "aVMem", "lVMem", "PMemF", "VMemF"] sortmethod = "aPMem" table.field_names = [ "User", "AVG PMem Used", "PMem Limit", "AVG VMem Used", "VMem Limit", "Limit Reached #", ] elif args.Proc: print(f"Printing {args.Time} process counts...") resources = ["ID", "aEP", "lEP", "EPf", "aNproc", "lNproc", "NprocF"] sortmethod = "aNproc" table.field_names = [ "User", "Entry Procs", "EP Limit", "EP Limit Reached #", "Total Procs", "Proc Limit", "Limit Reached #", ] elif args.IO: print(f"Printing {args.Time} IO usage statistics") resources = [ "ID", "aIO", "uIO", "lIO", "IOf", "aIOPS", "lIOPS", "IOPSf", ] sortmethod = "aIO" table.field_names = [ "User", "I/O", "%", "I/O Limit", "I/O Limit Reached #", "I/O Ops.", "I/O Ops. Limit", "Ops. Limit Reached #", ] elif args.Fault: print(f"Printing usage limits hit in the time period {args.Time}") resources = [ "ID", "CPUf", "EPf", "NprocF", "VMemF", "PMemF", "IOf", "IOPSf", ] sortmethod = "any_faults" table.field_names = [ "User", "CPU", "Entry Procs", "Total Procs", "Memory", "I/O", "I/O Ops.", ] if not args.Chart: # if we're doing anything but generating a chart, run lveinfo data = lveinfo(sortmethod, args.Time, ",".join(resources)) if data: # load lveinfo's json output into a dict data = json.loads(data) tablelist = [] iteration = 0 for user in data["data"]: if iteration == USERCOUNT: break # the info from lve isn't ordered. Put it in our desired order # based on the resources list userinfo = OrderedDict() mems = {"aPMem", "lPMem", "aVMem", "lVMem"} for resource in resources: # some special formatting e.g. sizes and percentages if resource in ("uCPU", "uIO"): user[resource] = f"{user[resource]:.0%}" if resource == "lCPU": user[resource] = user[resource] / 100.0 if resource in mems and isinstance(user[resource], int): user[resource] = sizeof_fmt(user[resource]) if resource in ["aIO", "lIO"]: user[resource] = sizeof_fmt(user[resource] * 1024) if "MemF" in resource: # Virtual and Physical Memory faults can be combined if "Memory" in user: userinfo["Memory"] += user[resource] else: userinfo["Memory"] = user[resource] else: userinfo[resource] = user[resource] tablelist.append(userinfo) iteration += 1 # send the collected data to pretty table tableify(table, tablelist) if __name__ == "__main__": main()