async def ping_check(self, data): try: cmd = ["ping", data["ip"]] r = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) stdout, stderr = await r.communicate() success = ["Reply", "bytes", "time", "TTL"] if stdout: output = stdout.decode("utf-8", errors="ignore") if all(x in output for x in success): status = "passing" else: status = "failing" elif stderr: status = "failing" output = stderr.decode("utf-8", errors="ignore") payload = { "status": status, "more_info": output, } self.logger.debug(payload) resp = requests.patch( f"{self.astor.server}/api/v1/{data['id']}/checkrunner/", json.dumps(payload), headers=self.headers, timeout=15, ) if ( status == "failing" and data["assigned_task"] and data["assigned_task"]["enabled"] ): from taskrunner import TaskRunner task = TaskRunner( task_pk=data["assigned_task"]["id"], log_level=self.log_level, log_to=self.log_to, ) await task.run_while_in_event_loop() return status except Exception as e: self.logger.debug(e) return "failing"
async def disk_check(self, data, exists=True): try: disk = psutil.disk_usage(data["disk"]) except Exception: exists = False self.logger.error(f"Disk {data['disk']} does not exist") if exists: percent_used = round(disk.percent) total = bytes2human(disk.total) free = bytes2human(disk.free) if (100 - percent_used) < data["threshold"]: status = "failing" else: status = "passing" more_info = f"Total: {total}B, Free: {free}B" else: status = "failing" more_info = f"Disk {data['disk']} does not exist" payload = { "status": status, "more_info": more_info, } self.logger.debug(payload) resp = requests.patch( f"{self.astor.server}/api/v1/{data['id']}/checkrunner/", json.dumps(payload), headers=self.headers, timeout=15, ) if ( status == "failing" and data["assigned_task"] and data["assigned_task"]["enabled"] ): from taskrunner import TaskRunner task = TaskRunner( task_pk=data["assigned_task"]["id"], log_level=self.log_level, log_to=self.log_to, ) await task.run_while_in_event_loop() return status
# so that people can have different configs for different builds # prepare the environment file config_env = config.asDict() config_env.update(os.environ) if myconfig: config_env.update(myconfig.asDict()) tasks = Task([ Job("pre-flight", "./scripts/pre-flight.sh", env=config_env), Job("win_build", "./scripts/build-windows.sh", env=config_env), Job("lin_build", "./scripts/build-linux.sh", env=config_env), Job("mac_build", "./scripts/build-mac.sh", env=config_env), ]) print "Build getting started at: ", time.ctime() # Run the first task, which will create the docs and sources tarballs tr = TaskRunner(tasks) rc = tr.run() if rc == 0 and config.delete_temps == "yes": shutil.rmtree(config.WX_TEMP_DIR) # cleanup the DAILY_BUILD file if config.KIND == "daily": os.unlink("DAILY_BUILD") print "Build finished at: ", time.ctime() sys.exit(0)
import sys from taskrunner import Task, TaskRunner if __name__ == '__main__': # setup taskrunner taskRunner = TaskRunner( enableHelp = True, defaultTask = Task('default', 'qs version && printf \"\n\" && qs help'), versionTask = Task(['v', 'version'], 'echo \"QuickScript Version 1.3\nCreated by Nicholas Ramsay \"', 'Shows the current QuickScript version.') ) # get tasks from file and add to taskRunner with open('tasks.csv', 'r') as f: for l in f.readlines(0): segments = l.split(', ') taskRunner.AddTask(Task(segments[0].split(' '), segments[1], segments[2])) # Run the command line argument task try: if len(sys.argv[1:]) < 1: taskRunner.RunTask('') else: for arg in sys.argv[1:]: taskRunner.RunTask(arg) except Exception as e: print('\033[91m' + str(e) + '\033[0m\n') taskRunner.RunTask('help')
async def script_check(self, data): try: script_path = data["script"]["filepath"] shell = data["script"]["shell"] timeout = data["timeout"] script_filename = data["script"]["filename"] if shell == "python": cmd = [ self.salt_call, "win_agent.run_python_script", script_filename, f"timeout={timeout}", ] try: script_type = data["script"]["script_type"] except KeyError: pass else: cmd.append(f"script_type={script_type}") else: cmd = [ self.salt_call, "cmd.script", script_path, f"shell={shell}", f"timeout={timeout}", ] self.logger.debug(cmd) start = perf_counter() proc = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) proc_timeout = int(timeout) + 2 try: proc_stdout, proc_stderr = await asyncio.wait_for( proc.communicate(), proc_timeout ) except asyncio.TimeoutError: try: proc.terminate() except: pass self.logger.debug(f"Script check timed out after {timeout} seconds") proc_stdout, proc_stderr = False, False stdout = "" stderr = f"Script timed out after {timeout} seconds" retcode = 98 stop = perf_counter() if proc_stdout: resp = json.loads(proc_stdout.decode("utf-8", errors="ignore")) retcode = resp["local"]["retcode"] stdout = resp["local"]["stdout"] stderr = resp["local"]["stderr"] elif proc_stderr: retcode = 99 stdout = "" stderr = proc_stderr.decode("utf-8", errors="ignore") if retcode != 0: status = "failing" else: status = "passing" payload = { "stdout": stdout, "stderr": stderr, "status": status, "retcode": retcode, "execution_time": "{:.4f}".format(round(stop - start)), } self.logger.debug(payload) resp = requests.patch( f"{self.astor.server}/api/v1/{data['id']}/checkrunner/", json.dumps(payload), headers=self.headers, timeout=15, ) if ( status == "failing" and data["assigned_task"] and data["assigned_task"]["enabled"] ): from taskrunner import TaskRunner task = TaskRunner( task_pk=data["assigned_task"]["id"], log_level=self.log_level, log_to=self.log_to, ) await task.run_while_in_event_loop() return status except Exception as e: self.logger.debug(e) return "failing"
async def event_log_check(self, data): try: log = [] api_log_name = data["log_name"] api_event_id = int(data["event_id"]) api_event_type = data["event_type"] api_fail_when = data["fail_when"] api_search_last_days = int(data["search_last_days"]) try: api_event_id_is_wildcard = data["event_id_is_wildcard"] except KeyError: api_event_id_is_wildcard = False if api_search_last_days != 0: start_time = dt.datetime.now() - dt.timedelta(days=api_search_last_days) flags = ( win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ ) status_dict = { win32con.EVENTLOG_AUDIT_FAILURE: "AUDIT_FAILURE", win32con.EVENTLOG_AUDIT_SUCCESS: "AUDIT_SUCCESS", win32con.EVENTLOG_INFORMATION_TYPE: "INFO", win32con.EVENTLOG_WARNING_TYPE: "WARNING", win32con.EVENTLOG_ERROR_TYPE: "ERROR", 0: "INFO", } hand = win32evtlog.OpenEventLog("localhost", api_log_name) total = win32evtlog.GetNumberOfEventLogRecords(hand) uid = 0 done = False while 1: events = win32evtlog.ReadEventLog(hand, flags, 0) for ev_obj in events: uid += 1 # return once total number of events reach or we'll be stuck in an infinite loop if uid >= total: done = True break the_time = ev_obj.TimeGenerated.Format() time_obj = dt.datetime.strptime(the_time, "%c") if api_search_last_days != 0: if time_obj < start_time: done = True break computer = str(ev_obj.ComputerName) src = str(ev_obj.SourceName) evt_type = str(status_dict[ev_obj.EventType]) evt_id = str(winerror.HRESULT_CODE(ev_obj.EventID)) evt_category = str(ev_obj.EventCategory) record = str(ev_obj.RecordNumber) msg = ( str(win32evtlogutil.SafeFormatMessage(ev_obj, api_log_name)) .replace("<", "") .replace(">", "") ) event_dict = { "computer": computer, "source": src, "eventType": evt_type, "eventID": evt_id, "eventCategory": evt_category, "message": msg, "time": the_time, "record": record, "uid": uid, } if api_event_id_is_wildcard and evt_type == api_event_type: log.append(event_dict) elif int(evt_id) == api_event_id and evt_type == api_event_type: log.append(event_dict) if done: break win32evtlog.CloseEventLog(hand) if api_fail_when == "contains": if log: status = "failing" more_info = {"log": log} else: status = "passing" more_info = {"log": []} elif api_fail_when == "not_contains": if log: status = "passing" more_info = {"log": log} else: status = "failing" more_info = {"log": []} else: status = "failing" more_info = {"log": []} payload = { "status": status, "extra_details": more_info, } self.logger.debug(payload) resp = requests.patch( f"{self.astor.server}/api/v1/{data['id']}/checkrunner/", json.dumps(payload), headers=self.headers, timeout=15, ) if ( status == "failing" and data["assigned_task"] and data["assigned_task"]["enabled"] ): from taskrunner import TaskRunner task = TaskRunner( task_pk=data["assigned_task"]["id"], log_level=self.log_level, log_to=self.log_to, ) await task.run_while_in_event_loop() return status except Exception as e: self.logger.debug(e) return "failing"
async def win_service_check(self, data, exists=True): try: services = self.get_services() try: service = list( filter(lambda x: x["name"] == data["svc_name"], services) )[0] except IndexError: exists = False self.logger.error(f"Service {data['svc_name']} does not exist") if exists: service_status = service["status"] if service_status == "running": status = "passing" elif ( service_status == "start_pending" and data["pass_if_start_pending"] ): status = "passing" else: status = "failing" if data["restart_if_stopped"]: ret = self.salt_call_ret_bool( cmd="service.restart", args=[data["svc_name"]], timeout=60, ) # wait a bit to give service time to start before checking status again await asyncio.sleep(10) reloaded = self.get_services() stat = list( filter(lambda x: x["name"] == data["svc_name"], reloaded) )[0]["status"] if stat == "running": status = "passing" elif stat == "start_pending" and data["pass_if_start_pending"]: status = "passing" else: status = "failing" service_status = stat else: status = "failing" payload = { "status": status, "more_info": f"Status {service_status.upper()}" if exists else f"Service {data['svc_name']} does not exist", } self.logger.debug(payload) resp = requests.patch( f"{self.astor.server}/api/v1/{data['id']}/checkrunner/", json.dumps(payload), headers=self.headers, timeout=15, ) if ( status == "failing" and data["assigned_task"] and data["assigned_task"]["enabled"] ): from taskrunner import TaskRunner task = TaskRunner( task_pk=data["assigned_task"]["id"], log_level=self.log_level, log_to=self.log_to, ) await task.run_while_in_event_loop() return status except Exception as e: self.logger.debug(e) return "failing"
from taskrunner import TaskRunner tr = TaskRunner('cluster') tr.run_build() print(tr.run_job())
def main(): parser = argparse.ArgumentParser(description="Tactical RMM Agent") parser.add_argument("-m", action="store", dest="mode", type=str) parser.add_argument("-p", action="store", dest="taskpk", type=int) parser.add_argument("--api", action="store", dest="api_url", type=str) parser.add_argument("--client-id", action="store", dest="client_id", type=int) parser.add_argument("--site-id", action="store", dest="site_id", type=int) parser.add_argument( "--desc", action="store", dest="agent_desc", type=str, default="changeme" ) parser.add_argument( "--agent-type", action="store", dest="agent_type", type=str, default="server", choices=["server", "workstation"], ) parser.add_argument("--auth", action="store", dest="auth_token", type=str) args = parser.parse_args() if args.mode == "install": import sys import threading if len(sys.argv) != 15: parser.print_help() raise SystemExit() from installer import Installer installer = Installer( api_url=args.api_url, client_id=args.client_id, site_id=args.site_id, agent_desc=args.agent_desc, agent_type=args.agent_type, auth_token=args.auth_token, ) t = threading.Thread(target=installer.install, daemon=True) t.start() t.join() elif args.mode == "winagentsvc": from winagentsvc import WinAgentSvc agent = WinAgentSvc() agent.run() elif args.mode == "checkrunner": from checkrunner import CheckRunner agent = CheckRunner() agent.run_forever() elif args.mode == "runchecks": from checkrunner import CheckRunner agent = CheckRunner() agent.run() elif args.mode == "winupdater": from winupdater import WinUpdater agent = WinUpdater() agent.install_all() elif args.mode == "patchscan": from winupdater import WinUpdater agent = WinUpdater() agent.trigger_patch_scan() elif args.mode == "taskrunner": from taskrunner import TaskRunner agent = TaskRunner(task_pk=args.taskpk) agent.run() elif args.mode == "updatesalt": from agent import WindowsAgent agent = WindowsAgent() agent.fix_salt(by_time=False) agent.update_salt() elif args.mode == "fixsalt": from agent import WindowsAgent agent = WindowsAgent() agent.fix_salt() elif args.mode == "fixmesh": from agent import WindowsAgent agent = WindowsAgent() agent.fix_mesh() elif args.mode == "cleanup": from agent import WindowsAgent agent = WindowsAgent() agent.fix_salt(by_time=False) agent.cleanup() else: import win32gui from agent import show_agent_status window = win32gui.GetForegroundWindow() if window == 0: # called from cli with no interactive desktop show_agent_status(window=None, gui=False) else: show_agent_status(window=window, gui=True)
def main(): parser = argparse.ArgumentParser(description="Tactical RMM Agent") parser.add_argument("-m", action="store", dest="mode", type=str) parser.add_argument("-p", action="store", dest="taskpk", type=int) parser.add_argument("--api", action="store", dest="api_url", type=str) parser.add_argument("--client-id", action="store", dest="client_id", type=int) parser.add_argument("--site-id", action="store", dest="site_id", type=int) parser.add_argument( "--desc", action="store", dest="agent_desc", type=str, default=socket.gethostname(), ) parser.add_argument( "--agent-type", action="store", dest="agent_type", type=str, default="server", choices=["server", "workstation"], ) parser.add_argument( "-l", "--log", action="store", dest="log_level", type=str, default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], ) parser.add_argument( "--logto", action="store", dest="log_to", type=str, default="file", choices=["file", "stdout"], ) parser.add_argument( "--power", action="store", dest="power", type=int, default=0, choices=[0, 1], ) parser.add_argument( "--rdp", action="store", dest="rdp", type=int, default=0, choices=[0, 1], ) parser.add_argument( "--ping", action="store", dest="ping", type=int, default=0, choices=[0, 1], ) parser.add_argument("--auth", action="store", dest="auth_token", type=str) parser.add_argument("--version", action="store_true") parser.add_argument( "--local-salt", action="store", dest="local_salt", type=str, help= r'The full path to the salt-minion executable e.g. "C:\\temp\\salt-minion-setup.exe"', ) parser.add_argument( "--local-mesh", action="store", dest="local_mesh", type=str, help= r'The full path to the Mesh Agent executable e.g. "C:\\temp\\meshagent.exe"', ) args = parser.parse_args() if args.version: try: with open( os.path.join("C:\\Program Files\\TacticalAgent", "VERSION")) as f: ver = f.read().strip() print(ver) except Exception as e: print(f"Error getting version: {e}") elif args.mode == "install": if (not args.api_url or not args.client_id or not args.site_id or not args.auth_token): parser.print_help() sys.exit(1) if args.local_salt: if not os.path.exists(args.local_salt): parser.print_help() sys.stdout.flush() print(f"\nError: {args.local_salt} does not exist\n", flush=True) sys.exit(1) if not os.path.isfile(args.local_salt): parser.print_help() sys.stdout.flush() print( f"\nError: {args.local_salt} must be a file, not a folder.", flush=True, ) print( r'Make sure to use double backslashes for file paths, and double quotes e.g. "C:\\temp\\salt-minion-setup.exe"', flush=True, ) print("", flush=True) sys.exit(1) if args.local_mesh: if not os.path.exists(args.local_mesh): parser.print_help() sys.stdout.flush() print(f"\nError: {args.local_mesh} does not exist\n", flush=True) sys.exit(1) if not os.path.isfile(args.local_mesh): parser.print_help() sys.stdout.flush() print( f"\nError: {args.local_mesh} must be a file, not a folder.", flush=True, ) print( r'Make sure to use double backslashes for file paths, and double quotes e.g. "C:\\temp\\meshagent.exe"', flush=True, ) print("", flush=True) sys.exit(1) from installer import Installer installer = Installer( api_url=args.api_url, client_id=args.client_id, site_id=args.site_id, agent_desc=args.agent_desc, agent_type=args.agent_type, power=args.power, rdp=args.rdp, ping=args.ping, auth_token=args.auth_token, log_level=args.log_level, local_salt=args.local_salt, local_mesh=args.local_mesh, ) installer.install() elif args.mode == "winagentsvc": from winagentsvc import WinAgentSvc agent = WinAgentSvc(log_level=args.log_level, log_to=args.log_to) agent.run() elif args.mode == "checkrunner": from checkrunner import CheckRunner agent = CheckRunner(log_level=args.log_level, log_to=args.log_to) agent.run_forever() elif args.mode == "runchecks": from checkrunner import CheckRunner agent = CheckRunner(log_level=args.log_level, log_to=args.log_to) agent.run() elif args.mode == "winupdater": from winupdater import WinUpdater agent = WinUpdater(log_level=args.log_level, log_to=args.log_to) agent.install_all() elif args.mode == "patchscan": from winupdater import WinUpdater agent = WinUpdater(log_level=args.log_level, log_to=args.log_to) agent.trigger_patch_scan() elif args.mode == "taskrunner": from taskrunner import TaskRunner agent = TaskRunner(task_pk=args.taskpk, log_level=args.log_level, log_to=args.log_to) agent.run() elif args.mode == "updatesalt": from agent import WindowsAgent agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to) agent.fix_salt(by_time=False) agent.update_salt() elif args.mode == "fixsalt": from agent import WindowsAgent agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to) agent.fix_salt() elif args.mode == "fixmesh": from agent import WindowsAgent agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to) agent.fix_mesh() elif args.mode == "cleanup": from agent import WindowsAgent agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to) agent.fix_salt(by_time=False) agent.cleanup() elif args.mode == "recoversalt": from agent import WindowsAgent agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to) agent.recover_salt() elif args.mode == "recovermesh": from agent import WindowsAgent agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to) agent.recover_mesh() else: import win32gui from agent import show_agent_status window = win32gui.GetForegroundWindow() if window == 0: # called from cli with no interactive desktop show_agent_status(window=None, gui=False) else: show_agent_status(window=window, gui=True)