def handle_bulk_script_task(scriptpk, agentpks, args, timeout): script = Script.objects.get(pk=scriptpk) agents = Agent.objects.filter(pk__in=agentpks) agents_nats = [agent for agent in agents if agent.has_nats] agents_salt = [agent for agent in agents if not agent.has_nats] minions = [agent.salt_id for agent in agents_salt] if minions: Agent.salt_batch_async( minions=minions, func="win_agent.run_script", kwargs={ "filepath": script.filepath, "filename": script.filename, "shell": script.shell, "timeout": timeout, "args": args, "bg": True if script.shell == "python" else False, # salt bg script bug }, ) nats_data = { "func": "runscript", "timeout": timeout, "script_args": args, "payload": { "code": script.code, "shell": script.shell, }, } for agent in agents_nats: asyncio.run(agent.nats_cmd(nats_data, wait=False))
def handle_bulk_command_task(agentpks, cmd, shell, timeout): agents = Agent.objects.filter(pk__in=agentpks) agents_nats = [agent for agent in agents if agent.has_nats] agents_salt = [agent for agent in agents if not agent.has_nats] minions = [agent.salt_id for agent in agents_salt] if minions: Agent.salt_batch_async( minions=minions, func="cmd.run_bg", kwargs={ "cmd": cmd, "shell": shell, "timeout": timeout, }, ) if agents_nats: nats_data = { "func": "rawcmd", "timeout": timeout, "payload": { "command": cmd, "shell": shell, }, } for agent in agents_nats: asyncio.run(agent.nats_cmd(nats_data, wait=False))
def batch_sync_modules_task(): # sync modules, split into chunks of 50 agents to not overload salt agents = Agent.objects.all() online = [i.salt_id for i in agents] chunks = (online[i:i + 50] for i in range(0, len(online), 50)) for chunk in chunks: Agent.salt_batch_async(minions=chunk, func="saltutil.sync_modules") sleep(10)
def batch_sysinfo_task(): # update system info using WMI agents = Agent.objects.all() online = [ i.salt_id for i in agents if not i.not_supported("0.11.0") and i.status == "online" ] chunks = (online[i:i + 30] for i in range(0, len(online), 30)) for chunk in chunks: Agent.salt_batch_async(minions=chunk, func="win_agent.local_sys_info") sleep(10)
def send_agent_update_task(pks, version): assert isinstance(pks, list) ver = version.split("winagent-v")[1] q = Agent.objects.only("pk").filter(pk__in=pks) agents = [ i for i in q if pyver.parse(i.version) < pyver.parse(ver) and i.status == "online" ] if agents: for agent in agents: agent.update_pending = True agent.save(update_fields=["update_pending"]) minions = [i.salt_id for i in agents] r = Agent.get_github_versions() git_versions = r["versions"] data = r["data"] # full response from github versions = {} for i, release in enumerate(data): versions[i] = release["name"] key = [k for k, v in versions.items() if v == version][0] download_url = data[key]["assets"][0]["browser_download_url"] # split into chunks to not overload salt chunks = (minions[i : i + 30] for i in range(0, len(minions), 30)) for chunk in chunks: r = Agent.salt_batch_async( minions=chunk, func="win_agent.do_agent_update", kwargs={"version": ver, "url": download_url}, ) sleep(5)
def handle(self, *args, **kwargs): # sync modules. split into chunks of 30 agents to not overload the salt master agents = Agent.objects.all() online = [i.salt_id for i in agents if i.status == "online"] chunks = (online[i:i + 30] for i in range(0, len(online), 30)) self.stdout.write(self.style.SUCCESS("Syncing agent modules...")) for chunk in chunks: r = Agent.salt_batch_async(minions=chunk, func="saltutil.sync_modules") sleep(5) has_old_config = True rmm_conf = "/etc/nginx/sites-available/rmm.conf" if os.path.exists(rmm_conf): with open(rmm_conf) as f: for line in f: if "location" and "builtin" in line: has_old_config = False break if has_old_config: new_conf = """ location /builtin/ { internal; add_header "Access-Control-Allow-Origin" "https://rmm.yourwebsite.com"; alias /srv/salt/scripts/; } """ after_this = """ location /saltscripts/ { internal; add_header "Access-Control-Allow-Origin" "https://rmm.yourwebsite.com"; alias /srv/salt/scripts/userdefined/; } """ self.stdout.write(self.style.ERROR("*" * 100)) self.stdout.write("\n") self.stdout.write( self.style.ERROR( "WARNING: A recent update requires you to manually edit your nginx config" )) self.stdout.write("\n") self.stdout.write( self.style.ERROR("Please add the following location block to ") + self.style.WARNING(rmm_conf)) self.stdout.write(self.style.SUCCESS(new_conf)) self.stdout.write("\n") self.stdout.write( self.style.ERROR( "You can paste the above right after the following block that's already in your nginx config:" )) self.stdout.write(after_this) self.stdout.write("\n") self.stdout.write( self.style.ERROR( "Make sure to replace rmm.yourwebsite.com with your domain" )) self.stdout.write( self.style.ERROR( "After editing, restart nginx with the command ") + self.style.WARNING("sudo systemctl restart nginx")) self.stdout.write("\n") self.stdout.write(self.style.ERROR("*" * 100)) input("Press Enter to continue...") # install go if not os.path.exists("/usr/local/rmmgo/"): self.stdout.write(self.style.SUCCESS("Installing golang")) subprocess.run("sudo mkdir -p /usr/local/rmmgo", shell=True) tmpdir = tempfile.mkdtemp() r = subprocess.run( f"wget https://golang.org/dl/go1.15.linux-amd64.tar.gz -P {tmpdir}", shell=True, ) gotar = os.path.join(tmpdir, "go1.15.linux-amd64.tar.gz") subprocess.run(f"tar -xzf {gotar} -C {tmpdir}", shell=True) gofolder = os.path.join(tmpdir, "go") subprocess.run(f"sudo mv {gofolder} /usr/local/rmmgo/", shell=True) shutil.rmtree(tmpdir)
def handle(self, *args, **kwargs): if not os.path.exists("/usr/local/bin/goversioninfo"): self.stdout.write(self.style.ERROR("*" * 100)) self.stdout.write("\n") self.stdout.write( self.style.ERROR( "ERROR: New update script available. Delete this one and re-download." )) self.stdout.write("\n") sys.exit(1) # 10-16-2020 changed the type of the agent's 'disks' model field # from a dict of dicts, to a list of disks in the golang agent # the following will convert dicts to lists for agent's still on the python agent agents = Agent.objects.all() for agent in agents: if agent.disks is not None and isinstance(agent.disks, dict): new = [] for k, v in agent.disks.items(): new.append(v) agent.disks = new agent.save(update_fields=["disks"]) self.stdout.write( self.style.SUCCESS(f"Migrated disks on {agent.hostname}")) # sync modules. split into chunks of 60 agents to not overload the salt master agents = Agent.objects.all() online = [i.salt_id for i in agents if i.status == "online"] chunks = (online[i:i + 60] for i in range(0, len(online), 60)) self.stdout.write(self.style.SUCCESS("Syncing agent modules...")) for chunk in chunks: r = Agent.salt_batch_async(minions=chunk, func="saltutil.sync_modules") sleep(5) has_old_config = True rmm_conf = "/etc/nginx/sites-available/rmm.conf" if os.path.exists(rmm_conf): with open(rmm_conf) as f: for line in f: if "location" and "builtin" in line: has_old_config = False break if has_old_config: new_conf = """ location /builtin/ { internal; add_header "Access-Control-Allow-Origin" "https://rmm.yourwebsite.com"; alias /srv/salt/scripts/; } """ after_this = """ location /saltscripts/ { internal; add_header "Access-Control-Allow-Origin" "https://rmm.yourwebsite.com"; alias /srv/salt/scripts/userdefined/; } """ self.stdout.write(self.style.ERROR("*" * 100)) self.stdout.write("\n") self.stdout.write( self.style.ERROR( "WARNING: A recent update requires you to manually edit your nginx config" )) self.stdout.write("\n") self.stdout.write( self.style.ERROR("Please add the following location block to ") + self.style.WARNING(rmm_conf)) self.stdout.write(self.style.SUCCESS(new_conf)) self.stdout.write("\n") self.stdout.write( self.style.ERROR( "You can paste the above right after the following block that's already in your nginx config:" )) self.stdout.write(after_this) self.stdout.write("\n") self.stdout.write( self.style.ERROR( "Make sure to replace rmm.yourwebsite.com with your domain" )) self.stdout.write( self.style.ERROR( "After editing, restart nginx with the command ") + self.style.WARNING("sudo systemctl restart nginx")) self.stdout.write("\n") self.stdout.write(self.style.ERROR("*" * 100)) input("Press Enter to continue...") # install go if not os.path.exists("/usr/local/rmmgo/"): self.stdout.write(self.style.SUCCESS("Installing golang")) subprocess.run("sudo mkdir -p /usr/local/rmmgo", shell=True) tmpdir = tempfile.mkdtemp() r = subprocess.run( f"wget https://golang.org/dl/go1.15.linux-amd64.tar.gz -P {tmpdir}", shell=True, ) gotar = os.path.join(tmpdir, "go1.15.linux-amd64.tar.gz") subprocess.run(f"tar -xzf {gotar} -C {tmpdir}", shell=True) gofolder = os.path.join(tmpdir, "go") subprocess.run(f"sudo mv {gofolder} /usr/local/rmmgo/", shell=True) shutil.rmtree(tmpdir) # load community scripts into the db Script.load_community_scripts()