def remote_tellOutput(self, ip, output): """ ip:str | output:serializable -> None Marks completion in database Verifies job that client is returning """ # Get relevant assignment assignment = fi.job.model.Assignment.lookup(ip) # Mark it complete in database fi.job.model.Assignment.complete(ip, output) fi.logmsg( self.__class__, "Completed %d-%d-%d for %s" % ( assignment.job.id, assignment.instance.id, assignment.id, ip, ) ) # Verify returned result fi.job.verifier.Verifier.verify(assignment)
def schedule(cls, credits): """ credits:[(str, int)] -> None """ fi.logmsg(cls, "Scheduling") max_credit = max( credits, key=lambda x: x[1] )[1] # This right here is essentially the scheduling, converting the credit to proportional numbers logs = [ (ip, math.log1p(credit + 1)) for (ip, credit) in credits ] total_log = reduce( lambda x, y: x + y, (n for (_, n) in logs) ) allocations = ( (ip, (log / total_log) * fi.throttle.AVAILABLE_BANDWIDTH) for (ip, log) in logs ) return allocations
def onPathloadReceive(cls, data): """ data:str -> None Receives bandwidth data in form "float float" and sets max bandwidth Calls receive funciton again """ try: lines = data.split('\n') high = 0 low = 0 for line in lines: if 'Available' in line: words = line.split() low = float(words[4]) high = float(words[6]) if high and low: available = (high + low) / 8 / 2 * 1000 fi.logmsg(cls, "Setting new available bandwidth to ", available, "kbps") # Convert from Mbps to kBps and set to available bandwidth fi.throttle.AVAILABLE_BANDWIDTH = available except ValueError, e: fi.logmsg(cls, "Unsuccessful parsing for available bandwidth")
def toldBandwidth(self, bandwidth): fi.logmsg(self.__class__, "Told %dkbps" % bandwidth) ThrottleApplication.throttle( ((fi.throttle.VPN_SERVER_IP, bandwidth),) ) self.gotRoot(self.root)
def askBandwidth(self): fi.logmsg(self.__class__, "Ask bandwidth") bandwidth_d = self.root.callRemote( "tellBandwidth", self.ip ) bandwidth_d.addCallbacks( self.toldBandwidth, self.gotNothing, )
def toldJob(self, job): """ job:(str, str, serializable) -> None Called after job as been transferred """ # Unpack try: name, module_input, job_input = job except ValueError, e: fi.logmsg(self.__class__, "Invalid job") self.getRoot() return
def throttle(cls, allocations): """ allocations:[(str, int)] -> shell:fi.shell.Shell """ fi.logmsg(cls, "Making allocations") shell = fi.throttle.shell.Shell() interface = fi.throttle.VPN_INTERFACE toRun = ( # Drop current rules "/sbin/tc qdisc del dev %s root" % interface, "/sbin/iptables -t mangle -F", # Create queueing discipline on device root "/sbin/tc qdisc add dev %s root handle 1:0 htb" % interface, ) # Run above commands for command in toRun: shell.add(command) # Create node, filter, and /sbin/iptables mark rule for each client for i, (ip, allocation) in enumerate(allocations): bandwidth = float(allocation) * fi.throttle.BANDWIDTH_HEURISTIC # Create classes off of root qdisc shell.add("/sbin/tc class add dev %s parent 1: classid 1:%d htb rate %sbps prio %d" % ( interface, i + 1, bandwidth, i + 1 ) ) # Mark traffic shell.add("/sbin/iptables -t mangle -A POSTROUTING -d %s -j MARK --set-mark %d" % ( ip, i + 1 ) ) # Filter traffic shell.add("/sbin/tc filter add dev %s parent 1:0 protocol ip prio %d handle %d fw flowid 1:%d" % ( interface, i + 1, i + 1, i + 1 ) ) shell.execute()
class JobClientController(fi.controller.ClientController): def gotRoot(self, root): self.root = root self.askJob() def askJob(self, *args): # Ask for next job fi.logmsg(self.__class__, "Receiving Job") job_d = self.root.callRemote("tellJob", self.ip) job_d.addCallbacks(self.toldJob, self.gotNothing) def toldJob(self, job): """ job:(str, str, serializable) -> None Called after job as been transferred """ # Unpack try: name, module_input, job_input = job except ValueError, e: fi.logmsg(self.__class__, "Invalid job") self.getRoot() return fi.logmsg(self.__class__, "Running %s on %s" % (name, job_input)) # Load module into memory from code module = self.stringToModule(module_input, name) # Run job output = module.__getattribute__(name).getOutput(*job_input) fi.logmsg(self.__class__, "Returning job output") complete = self.root.callRemote( "tellOutput", self.ip, output, ) def askAnother(): complete.addCallbacks(self.askJob, self.gotNothing) fi.callLater(askAnother)
def remote_tellJob(self, ip): """ ip:str -> str | str | _ Gets the name, module code, and input list for the next job """ assignment = fi.job.model.Assignment.nextJob(ip) fi.job.model.Assignment.record(ip, assignment) fi.logmsg( self.__class__, "Assigning %d-%d-%d to %s" % ( assignment.job.id, assignment.instance.id, assignment.id, ip, )) return assignment.job.name, assignment.job.module, assignment.instance.input
def throttle(cls, allocations): """ allocations:[(str, int)] -> shell:fi.shell.Shell """ fi.logmsg(cls, "Making allocations") shell = fi.throttle.shell.Shell() interface = fi.throttle.VPN_INTERFACE toRun = ( # Drop current rules "/sbin/tc qdisc del dev %s root" % interface, "/sbin/iptables -t mangle -F", # Create queueing discipline on device root "/sbin/tc qdisc add dev %s root handle 1:0 htb" % interface, ) # Run above commands for command in toRun: shell.add(command) # Create node, filter, and /sbin/iptables mark rule for each client for i, (ip, allocation) in enumerate(allocations): bandwidth = float(allocation) * fi.throttle.BANDWIDTH_HEURISTIC # Create classes off of root qdisc shell.add( "/sbin/tc class add dev %s parent 1: classid 1:%d htb rate %sbps prio %d" % (interface, i + 1, bandwidth, i + 1)) # Mark traffic shell.add( "/sbin/iptables -t mangle -A POSTROUTING -d %s -j MARK --set-mark %d" % (ip, i + 1)) # Filter traffic shell.add( "/sbin/tc filter add dev %s parent 1:0 protocol ip prio %d handle %d fw flowid 1:%d" % (interface, i + 1, i + 1, i + 1)) shell.execute()
def schedule(cls, credits): """ credits:[(str, int)] -> None """ fi.logmsg(cls, "Scheduling") max_credit = max(credits, key=lambda x: x[1])[1] # This right here is essentially the scheduling, converting the credit to proportional numbers logs = [(ip, math.log1p(credit + 1)) for (ip, credit) in credits] total_log = reduce(lambda x, y: x + y, (n for (_, n) in logs)) allocations = ((ip, (log / total_log) * fi.throttle.AVAILABLE_BANDWIDTH) for (ip, log) in logs) return allocations
def remote_tellJob(self, ip): """ ip:str -> str | str | _ Gets the name, module code, and input list for the next job """ assignment = fi.job.model.Assignment.nextJob(ip) fi.job.model.Assignment.record(ip, assignment) fi.logmsg( self.__class__, "Assigning %d-%d-%d to %s" % ( assignment.job.id, assignment.instance.id, assignment.id, ip, ) ) return assignment.job.name, assignment.job.module, assignment.instance.input
def remote_tellOutput(self, ip, output): """ ip:str | output:serializable -> None Marks completion in database Verifies job that client is returning """ # Get relevant assignment assignment = fi.job.model.Assignment.lookup(ip) # Mark it complete in database fi.job.model.Assignment.complete(ip, output) fi.logmsg( self.__class__, "Completed %d-%d-%d for %s" % ( assignment.job.id, assignment.instance.id, assignment.id, ip, )) # Verify returned result fi.job.verifier.Verifier.verify(assignment)
def gotNothing(self, reason): """For callRemote failures""" fi.logmsg(self.__class__, "Remote call failed: " + str(reason))
def getRoot(self, *args): """Can be called to re-get the server root object""" fi.logmsg(self.__class__, "Receiving remote root") root_d = self.getRootObject() root_d.addCallbacks(self.gotRoot, self.gotNothing)
def clientConnectionFailed(self, connector, reason): fi.logmsg(self.__class__, "Connection lost") fi.callLater(connector.connect) fi.logmsg(self.__class__, "Reconnecting...")
def clientConnectionMade(self, connector): pb.PBClientFactory.clientConnectionMade(self, connector) fi.logmsg(self.__class__, "Connected to server") self.ip = connector.transport.getHost().host self.getRoot()
def askJob(self, *args): # Ask for next job fi.logmsg(self.__class__, "Receiving Job") job_d = self.root.callRemote("tellJob", self.ip) job_d.addCallbacks(self.toldJob, self.gotNothing)
def remote_tellBandwidth(self, ip): bandwidth = fi.throttle.model.Client.get_by(ip=ip).bandwidth fi.logmsg(self.__class__, "Tell %s %dkbps" % (ip, bandwidth)) return bandwidth