def main(args): qryr = SourceQuery(args[0], int(args[1])) sinfo = qryr.info() splayer = sorted(qryr.player(), key=lambda p: p['kills'], reverse=True) srules = qryr.rules() print sinfo['hostname'] print '*' * len(sinfo['hostname']) print print "(" + ("Linux" if sinfo['os'] == 'l' else "Windows") + " server, version " + str(sinfo['version']) + (", passworded" if sinfo['passworded'] == 1 else ', unpassworded') + ")" print print str(sinfo['numplayers']) + " of " + str(sinfo['maxplayers']) + " players mooching about:" for p in splayer: pname = "<unnamed>" if p['name'] == "" else p['name'] print " - " + pname + " (" + str(p['kills']) + " kills" + (" as they suck at this game" if p['kills'] == 0 else "") + ", connected for " + str(int(p['time'])) + "s)" print print "Current map is " + sinfo['map'] + ". Next is currently " + srules['sm_nextmap'] + "." + ("Learning through repetition!" if sinfo['map'] == srules['sm_nextmap'] else "") print print "Gravity is currently " + srules['sv_gravity'] print
def ezq(adr, port): """ ez-query, put in an ip/port, get out info, players, rules dictionaries. """ srcquery = SQ(adr, int(port)) players = srcquery.player() info = srcquery.info() rules = srcquery.rules() return info, players, rules
def __init__(self, logger, UpdateToolPath, serverDirectory, serverArgs): self.logger = logger self.serverDir = serverDirectory self.serverArgs = serverArgs self.serverConfig = NS2Config(serverArgs,serverDirectory) self.serverRcon = NS2Rcon(self,serverDirectory) self.restartWhenEmpty = False self.noUpdateCheck = False argParser = argparse.ArgumentParser(prog='NS2') argParser.add_argument('--restartwhenempty',action='store_true') argParser.add_argument('--noupdatecheck',action='store_true') try: parsed,otherargs = argParser.parse_known_args(serverArgs.split(' ')) self.restartWhenEmpty = parsed.restartwhenempty self.noUpdateCheck = parsed.noupdatecheck except: pass # have to do this after we parse the command line self.findUpdateTool(UpdateToolPath) # NS2 doesn't like extra command line args (and will die if they are present) self.serverArgs = self.serverArgs.replace('--restartwhenempty','').replace('--noupdatecheck','') # Query is one port higher then join self.serverPort = int(self.serverConfig['port'])+1 self.logger.info("Detected server IP as %s:%i" % (self.serverConfig['address'],self.serverPort)) self.queryObject = SourceQuery(self.serverConfig['address'],self.serverPort) if self.restartWhenEmpty: self.logger.info("Server will be automatically restarted when empty") else: self.logger.info("Server will *NOT* be automatically restarted when empty") if self.serverConfig['game'].lower().find("ns2gmovrmind") != -1: self.getTickrate = True self.logger.info("NSGmOvermind detected, tickrate stats are available") self.logger.debug("NS2GmOvermind query: %s:%i" % (self.serverConfig['address'],self.serverPort+1)) self.overmindQueryObject = SourceQuery(self.serverConfig['address'],self.serverPort+1) else: self.getTickrate = False self.logger.info("NS2GmOvermind *NOT* detected, tickrate stats unavailable")
def checkRestart() : status, home = getstatusoutput("echo $HOME") server = "confusedherring.com" dir = home + "/tmp/" files = os.listdir(dir) runningServers = getRunningServerNames() for file in files: print "file: %s" % file f = open(dir + file, 'r'); cmd = f.readline().strip(); matchobj = re.search('([a-zA-Z0-9\-]+)-(\d+)\.server', file) if matchobj == None: continue; servername = matchobj.group(1); server_running = 0 #except: wasnt working, so do it the long way for tmp_servername in runningServers: if servername == tmp_servername: server_running = 1; break; if server_running == 1: serverDetails = getConfigDetails(servername) query = SourceQuery(server, int(serverDetails['port'])) sinfo = query.info(); if int(sinfo['numplayers']) <= 1: print "1 or less"; restartServer([servername]) os.system("rm " + dir + file); else: startServer([servername]) os.system("rm " + dir + file);
def check_css(address, port=27015): try: css = SourceQuery(address, port) return css.info() except: return None
#!/usr/bin/python from SourceQuery import SourceQuery import sys server = SourceQuery('91.121.95.23', 27013) #print server.ping() print server.info() print server.player() print server.rules()
class NS2Update: # Handle to the process where the server is running serverProc = None # outputThread will be a seperate thread that is spawned to grab all the output from the server # It will push it all into outputQueue, as well as to serverLogFile # outputQueue is currently unused, but will ultimately allow actions to be taken based on log events outputQueue = None chatQueue = None outputThread = None serverLogFile = None # Time of the last update check lastCheck = 0 # How often we should check for updates. This is set by the update server checkDelay = 300 # What URL to grab the latest version from. Ideally we would grab this from the CDR on the fly # but that's not terribly resource-friendly to do versionURL = "http://ns2update.devicenull.org/ns2update/ns2version.txt" # What version of the software is the server currently running currentVersion = 0 # What arguments should we pass to the server on startup serverArgs = '' # Is the server empty or not? serverEmptyCount = 0 # Store the time we last started the server lastStart = 0 # Should we disable update checking? noUpdateCheck = False # This gets set to true when the server has had players on it hasHadPlayers = False # Store the last stats values lastCPU = 0 lastMemory = 0 lastTickrate = 0 def __init__(self, logger, UpdateToolPath, serverDirectory, serverArgs): self.logger = logger self.serverDir = serverDirectory self.serverArgs = serverArgs self.serverConfig = NS2Config(serverArgs,serverDirectory) self.serverRcon = NS2Rcon(self,serverDirectory) self.restartWhenEmpty = False self.noUpdateCheck = False argParser = argparse.ArgumentParser(prog='NS2') argParser.add_argument('--restartwhenempty',action='store_true') argParser.add_argument('--noupdatecheck',action='store_true') try: parsed,otherargs = argParser.parse_known_args(serverArgs.split(' ')) self.restartWhenEmpty = parsed.restartwhenempty self.noUpdateCheck = parsed.noupdatecheck except: pass # have to do this after we parse the command line self.findUpdateTool(UpdateToolPath) # NS2 doesn't like extra command line args (and will die if they are present) self.serverArgs = self.serverArgs.replace('--restartwhenempty','').replace('--noupdatecheck','') # Query is one port higher then join self.serverPort = int(self.serverConfig['port'])+1 self.logger.info("Detected server IP as %s:%i" % (self.serverConfig['address'],self.serverPort)) self.queryObject = SourceQuery(self.serverConfig['address'],self.serverPort) if self.restartWhenEmpty: self.logger.info("Server will be automatically restarted when empty") else: self.logger.info("Server will *NOT* be automatically restarted when empty") if self.serverConfig['game'].lower().find("ns2gmovrmind") != -1: self.getTickrate = True self.logger.info("NSGmOvermind detected, tickrate stats are available") self.logger.debug("NS2GmOvermind query: %s:%i" % (self.serverConfig['address'],self.serverPort+1)) self.overmindQueryObject = SourceQuery(self.serverConfig['address'],self.serverPort+1) else: self.getTickrate = False self.logger.info("NS2GmOvermind *NOT* detected, tickrate stats unavailable") def findUpdateTool(self,extraPath): if self.noUpdateCheck: self.logger.info("Update checking disabled, not looking for hldsupdatetool") return paths = [ "../hldsupdatetool.exe", "hldsupdatetool.exe" ] if extraPath != None and extraPath != '': paths.append(extraPath) self.updatePath = "" for cur in paths: if os.path.exists(cur): self.updatePath = cur if self.updatePath == "": self.logger.critical("Unable to find hldsupdatetool.exe, please copy to server directory or see README") raise NameError("Unable to find hldsupdatetool.exe") def doUpdate(self): self.logger.info("Starting server update") update = subprocess.Popen("%s -command update -game naturalselection2 -dir %s" % (self.updatePath,self.serverDir)) if update: while update.returncode == None: time.sleep(5) update.poll() self.logger.info("Server update complete!") def startServer(self): # If we are starting the server, it must be empty self.serverEmptyCount = 0 self.hasHadPlayers = False self.lastStart = time.time() # Actually start the server process self.serverProc = subprocess.Popen("Server.exe %s" % self.serverArgs, stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.logger.info("Server started, pid %i version %s" % (self.serverProc.pid,self.currentVersion)) # Open up the log file logName = strftime("%Y.%m.%d.%H%M.log") self.logger.debug("Logging to %s" % logName) self.serverLogFile = open("serverlogs/%s" % logName,"a") # Setup everything we need to capture the server output self.outputQueue = Queue() self.chatQueue = Queue() self.outputThread = Thread(target=enqueue_output, args=(self.serverProc.stdout, self.outputQueue, self.serverLogFile, self.chatQueue)) self.outputThread.daemon = True self.outputThread.start() self.outputQueue.put("*** SERVER STARTED ***\n") def stopServer(self): if self.serverProc != None: self.logger.info("Killing server") self.serverProc.kill() self.cleanupServer() def cleanupServer(self): if self.outputThread != None: self.outputThread.join() if self.serverLogFile != None: self.serverLogFile.close() self.outputThread = None self.serverLogFile = None self.serverProc = None # Tickrate is currently unsupported, but adding it here is easier then modfiying rrd's later def recordStats(self,players,tickrate): if not os.path.exists("%s/rrdtool.exe" % self.serverDir): return statsFile = "%s/ns2update.rrd" % (self.serverDir) if not os.path.exists(statsFile): #os.system("\"%s/rrdtool.exe\" create \"%s\" DS:memory:GAUGE:300:0:U DS:cpu:GAUGE:600:0:U DS:players:GAUGE:600:0:U DS:tickrate:GAUGE:600:0:U RRA:LAST:0.5:1:2016 RRA:AVERAGE:0.5:2:2016" % (self.serverDir,statsFile)) subprocess.Popen(["%s/rrdtool.exe" % self.serverDir, "create", statsFile, "DS:memory:GAUGE:300:0:U", "DS:cpu:GAUGE:600:0:U", "DS:players:GAUGE:600:0:U", "DS:tickrate:GAUGE:600:0:U", "RRA:LAST:0.5:1:2016", "RRA:AVERAGE:0.5:2:2016"]) p = psutil.Process(self.serverProc.pid) cpu = p.get_cpu_percent(interval=1.0) meminfo = p.get_memory_info() rss = meminfo[0] / 1024 / 1024 self.logger.debug("CPU usage: %02i, memory: %04i MB, players: %02i tickrate: %02i" % (cpu, rss, players, int(tickrate))) self.lastCPU = cpu self.lastMemory = rss self.lastTickrate = tickrate #os.system("\"%s/rrdtool.exe\" update \"%s\" N:%i:%f:%i:%s" % (self.serverDir, statsFile, rss, cpu, players, tickrate)) subprocess.Popen(["%s/rrdtool.exe" % self.serverDir, "update", statsFile, "N:%i:%f:%i:%s" % (rss, cpu, players, tickrate)]) # Escape colons so rrdtool doesn't die statsFile = statsFile.replace(":","\\:") subprocess.Popen("\"%s/rrdtool.exe\" graph \"%s/ns2server.png\" --height 200 --width 400 --font DEFAULT:0:\"%s\"/rrdfont.ttf DEF:memory=\"%s\":memory:LAST CDEF:memorydisp=memory,10,/ DEF:cpu=\"%s\":cpu:LAST DEF:players=\"%s\":players:LAST DEF:tickrate=\"%s\":tickrate:LAST AREA:cpu#00FF00:\"%% CPU Usage\" LINE:memorydisp#FF0000:\"Memory usage (MB/10)\" LINE1:players#0000FF:\"Players\" LINE1:tickrate#000000:\"Tickrate\"" % (self.serverDir, self.serverDir, self.serverDir, statsFile, statsFile, statsFile, statsFile),stdout=subprocess.PIPE).wait() def think(self): if not self.noUpdateCheck and time.time() - self.lastCheck > self.checkDelay: self.logger.debug("Checking for server update...") data = urllib2.urlopen(self.versionURL) temp = data.read(100).split(",") if temp[0] > 0 and temp[1] > 60: desiredVersion = temp[0] if self.checkDelay != int(temp[1]): self.checkDelay = int(temp[1]) self.logger.debug("Setting update check delay to %i" % self.checkDelay) if desiredVersion > self.currentVersion: self.logger.info("Server is out of date: current: %s desired: %s" % (self.currentVersion,desiredVersion)) if self.serverProc != None: self.stopServer() if self.currentVersion == 0: self.logger.info("Performing inital server update") self.doUpdate() else: self.doUpdate() self.currentVersion = desiredVersion self.startServer() self.lastCheck = time.time() if self.serverProc == None: self.startServer() self.serverProc.poll() if self.serverProc.returncode != None: self.logger.critical("Server has died, restarting!") self.cleanupServer() self.startServer() currentPlayers = 0 tickrate = 0 # Don't check the server for 10s after it started (avoids issues with query not responding during startup) if time.time()-self.lastStart > 10: # If we are going to attempt to restart the server when it's empty, we need to query it.. try: details = self.queryObject.info() currentPlayers = details['numplayers'] if self.restartWhenEmpty: if details['numplayers'] == 0: self.serverEmptyCount += 1 else: self.serverEmptyCount = 0 self.hasHadPlayers = True if self.serverEmptyCount > 5 and self.hasHadPlayers: self.logger.info("Server now empty, restarting") self.stopServer() time.sleep(1) self.startServer() except IOError: pass try: if self.getTickrate: rules = self.overmindQueryObject.rules() tickrate = rules['netstat_tickrate'] except IOError: pass self.recordStats(currentPlayers,tickrate) # Use this to read console output without blocking #try: # while 1==1: # line = outQueue.get_nowait() #except Empty: # pass def sendCommand(self,command): print "Sending command: %s" % command self.serverProc.stdin.write("%s\r\n" % command)
def save(self): server = SQ(self.address, int(self.port)) self.name = server.info()['hostname'] self.slug = "{0}-{1}".format(self.address, self.port) super(Server, self).save()