def do_px(self, line): """Execute a Python statement. Node names may be used, e.g.: px print h1.cmd('ls')""" try: exec(line, globals(), self.getLocals()) except Exception as e: output(str(e) + '\n')
def do_dpctl(self, line): """Run dpctl (or ovs-ofctl) command on all switches. Usage: dpctl command [arg1] [arg2] ...""" args = line.split() if len(args) < 1: error('usage: dpctl command [arg1] [arg2] ...\n') return for sw in self.mn.switches: output('*** ' + sw.name + ' ' + ('-' * 72) + '\n') output(sw.dpctl(*args))
def iperf(self, hosts=None, l4Type='TCP', udpBw='10M', fmt=None, seconds=5, port=5001): """Run iperf between two hosts. hosts: list of hosts; if None, uses first and last hosts l4Type: string, one of [ TCP, UDP ] udpBw: bandwidth target for UDP test fmt: iperf format argument if any seconds: iperf time to transmit port: iperf port returns: two-element array of [ server, client ] speeds note: send() is buffered, so client rate can be much higher than the actual transmission rate; on an unloaded system, server rate should be much closer to the actual receive rate""" hosts = hosts or [self.hosts[0], self.hosts[-1]] assert len(hosts) == 2 client, server = hosts output('*** Iperf: testing', l4Type, 'bandwidth between', client, 'and', server, '\n') server.cmd('killall -9 iperf') iperfArgs = 'iperf -p %d ' % port bwArgs = '' if l4Type == 'UDP': iperfArgs += '-u ' bwArgs = '-b ' + udpBw + ' ' elif l4Type != 'TCP': raise Exception('Unexpected l4 type: %s' % l4Type) if fmt: iperfArgs += '-f %s ' % fmt server.sendCmd(iperfArgs + '-s') if l4Type == 'TCP': if not waitListening(client, server.IP(), port): raise Exception('Could not connect to iperf on port %d' % port) cliout = client.cmd(iperfArgs + '-t %d -c ' % seconds + server.IP() + ' ' + bwArgs) debug('Client output: %s\n' % cliout) servout = '' # We want the last *b/sec from the iperf server output # for TCP, there are two of them because of waitListening count = 2 if l4Type == 'TCP' else 1 while len(re.findall('/sec', servout)) < count: servout += server.monitor(timeoutms=5000) server.sendInt() servout += server.waitOutput() debug('Server output: %s\n' % servout) result = [self._parseIperf(servout), self._parseIperf(cliout)] if l4Type == 'UDP': result.insert(0, udpBw) output('*** Results: %s\n' % result) return result
def runCpuLimitTest(self, cpu, duration=5): """run CPU limit test with 'while true' processes. cpu: desired CPU fraction of each host duration: test duration in seconds (integer) returns a single list of measured CPU fractions as floats. """ pct = cpu * 100 info('*** Testing CPU %.0f%% bandwidth limit\n' % pct) hosts = self.hosts cores = int(quietRun('nproc')) # number of processes to run a while loop on per host num_procs = int(ceil(cores * cpu)) pids = {} for h in hosts: pids[h] = [] for _core in range(num_procs): h.cmd('while true; do a=1; done &') pids[h].append(h.cmd('echo $!').strip()) outputs = {} time = {} # get the initial cpu time for each host for host in hosts: outputs[host] = [] with open('/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' % host, 'r') as f: time[host] = float(f.read()) for _ in range(duration): sleep(1) for host in hosts: with open('/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' % host, 'r') as f: readTime = float(f.read()) outputs[host].append( ((readTime - time[host]) / 1000000000) / cores * 100) time[host] = readTime for h, pids in pids.items(): for pid in pids: h.cmd('kill -9 %s' % pid) cpu_fractions = [] for _host, outputs in outputs.items(): for pct in outputs: cpu_fractions.append(pct) output('*** Results: %s\n' % cpu_fractions) return cpu_fractions
def waitForNode(self, node): "Wait for a node to finish, and print its output." # Pollers nodePoller = poll() nodePoller.register(node.stdout) bothPoller = poll() bothPoller.register(self.stdin, POLLIN) bothPoller.register(node.stdout, POLLIN) if self.isatty(): # Buffer by character, so that interactive # commands sort of work quietRun('stty -icanon min 1') while True: try: bothPoller.poll() # XXX BL: this doesn't quite do what we want. if False and self.inputFile: key = self.inputFile.read(1) if key is not '': node.write(key) else: self.inputFile = None if isReadable(self.inPoller): key = self.stdin.read(1) node.write(key) if isReadable(nodePoller): data = node.monitor() output(data) if not node.waiting: break except KeyboardInterrupt: # There is an at least one race condition here, since # it's possible to interrupt ourselves after we've # read data but before it has been printed. node.sendInt() except select.error as e: # pylint: disable=unpacking-non-sequence errno_, errmsg = e.args # pylint: enable=unpacking-non-sequence if errno_ != errno.EINTR: error("select.error: %d, %s" % (errno_, errmsg)) node.sendInt()
def run(self): "Run our cmdloop(), catching KeyboardInterrupt" while True: try: # Make sure no nodes are still waiting for node in self.mn.values(): while node.waiting: info('stopping', node, '\n') node.sendInt() node.waitOutput() if self.isatty(): quietRun('stty echo sane intr ^C') self.cmdloop() break except KeyboardInterrupt: # Output a message - unless it's also interrupted # pylint: disable=broad-except try: output('\nInterrupt\n') except Exception: pass
def do_py(self, line): """Evaluate a Python expression. Node names may be used, e.g.: py h1.cmd('ls')""" try: result = eval(line, globals(), self.getLocals()) if not result: return elif isinstance(result, str): output(result + '\n') else: output(repr(result) + '\n') except Exception as e: output(str(e) + '\n')
def do_links(self, _line): "Report on links" for link in self.mn.links: output(link, link.status(), '\n')
def do_EOF(self, line): "Exit" output('\n') return self.do_exit(line)
def do_dump(self, _line): "Dump node info." for node in self.mn.values(): output('%s\n' % repr(node))
def do_intfs(self, _line): "List interfaces." for node in self.mn.values(): output('%s: %s\n' % (node.name, ','.join(node.intfNames())))
def do_nodes(self, _line): "List all nodes." nodes = ' '.join(sorted(self.mn)) output('available nodes are: \n%s\n' % nodes)
def do_help(self, line): "Describe available CLI commands." Cmd.do_help(self, line) if line is '': output(self.helpStr)
def pingFull(self, hosts=None, timeout=None): """Ping between all specified hosts and return all data. hosts: list of hosts timeout: time to wait for a response, as string returns: all ping data; see function body.""" # should we check if running? # Each value is a tuple: (src, dsd, [all ping outputs]) all_outputs = [] if not hosts: hosts = self.hosts output('*** Ping: testing ping reachability\n') for node in hosts: output('%s -> ' % node.name) for dest in hosts: if node != dest: opts = '' if timeout: opts = '-W %s' % timeout result = node.cmd('ping -c1 %s %s' % (opts, dest.IP())) outputs = self._parsePingFull(result) sent, received, rttmin, rttavg, rttmax, rttdev = outputs all_outputs.append((node, dest, outputs)) output(('%s ' % dest.name) if received else 'X ') output('\n') output("*** Results: \n") for outputs in all_outputs: src, dest, ping_outputs = outputs sent, received, rttmin, rttavg, rttmax, rttdev = ping_outputs output(" %s->%s: %s/%s, " % (src, dest, sent, received)) output("rtt min/avg/max/mdev %0.3f/%0.3f/%0.3f/%0.3f ms\n" % (rttmin, rttavg, rttmax, rttdev)) return all_outputs
def ping(self, hosts=None, timeout=None): """Ping between all specified hosts. hosts: list of hosts timeout: time to wait for a response, as string returns: ploss packet loss percentage""" # should we check if running? packets = 0 lost = 0 ploss = None if not hosts: hosts = self.hosts output('*** Ping: testing ping reachability\n') for node in hosts: output('%s -> ' % node.name) for dest in hosts: if node != dest: opts = '' if timeout: opts = '-W %s' % timeout if dest.intfs: result = node.cmd('ping -c1 %s %s' % (opts, dest.IP())) sent, received = self._parsePing(result) else: sent, received = 0, 0 packets += sent if received > sent: error('*** Error: received too many packets') error('%s' % result) node.cmdPrint('route') exit(1) lost += sent - received output(('%s ' % dest.name) if received else 'X ') output('\n') if packets > 0: ploss = 100.0 * lost / packets received = packets - lost output("*** Results: %i%% dropped (%d/%d received)\n" % (ploss, received, packets)) else: ploss = 0 output("*** Warning: No packets sent\n") return ploss