else:
return -errno.EINVAL, '', 'invalid command'
+ next_header_print = 0
+ # Set extra options for polling commands only:
+ if valid_dict.get('poll', False):
+ valid_dict['width'] = Termsize().cols
while True:
try:
- if next_header_print == 0:
+ # Only print the header for polling commands
+ if next_header_print == 0 and valid_dict.get('poll', False):
valid_dict['print_header'] = True
next_header_print = Termsize().rows - 3
next_header_print -= 1
ret, outbuf, outs = json_command(cluster_handle, target=target,
argdict=valid_dict, inbuf=inbuf)
- valid_dict['print_header'] = False
- if 'poll' not in valid_dict or not valid_dict['poll']:
+ if valid_dict.get('poll', False):
+ valid_dict['print_header'] = False
+ if not valid_dict.get('poll', False):
# Don't print here if it's not a polling command
break
if ret:
def handle_command(self, command):
rd = 0
wr = 0
- ops = 0
+ total = 0
+ rd_ops = 0
+ wr_ops = 0
+ total_ops = 0
ret = ''
if command['prefix'] == 'iostat':
if (stamp_delta > 0):
rd = int(r['pg_stats_delta']['stat_sum']['num_read_kb']) / stamp_delta
wr = int(r['pg_stats_delta']['stat_sum']['num_write_kb']) / stamp_delta
- ops = ( int(r['pg_stats_delta']['stat_sum']['num_write']) + int(r['pg_stats_delta']['stat_sum']['num_read']) ) / stamp_delta
+ # The values are in kB, but to_pretty_iec() requires them to be in bytes
+ rd = int(rd) << 10
+ wr = int(wr) << 10
+ total = rd + wr
- ret = "wr: {0} kB/s, rd: {1} kB/s, iops: {2}".format(int(wr), int(rd), int(ops))
+ rd_ops = int(r['pg_stats_delta']['stat_sum']['num_read']) / stamp_delta
+ wr_ops = int(r['pg_stats_delta']['stat_sum']['num_write']) / stamp_delta
+ total_ops = rd_ops + wr_ops
+
+ if 'width' in command:
+ width = command['width']
+ else:
+ width = 80
+
+ if command.get('print_header', False):
+ elems = ['Read', 'Write', 'Total', 'Read IOPS', 'Write IOPS', 'Total IOPS']
+ ret += self.get_pretty_header(elems, width)
+
+ elems = [
+ self.to_pretty_iec(rd) + 'B/s',
+ self.to_pretty_iec(wr) + 'B/s',
+ self.to_pretty_iec(total) + 'B/s',
+ int(rd_ops),
+ int(wr_ops),
+ int(total_ops)
+ ]
+ ret += self.get_pretty_row(elems, width)
elif command['prefix'] == 'iostat self-test':
r = self.get('io_rate')
return "/s"
elif unit == self.BYTES:
return "B/s"
-
+
+ def to_pretty_iec(self, n):
+ for bits, suffix in [(60, 'Ei'), (50, 'Pi'), (40, 'Ti'), (30, 'Gi'),
+ (20, 'Mi'), (10, 'Ki')]:
+ if n > 10 << bits:
+ return str(n >> bits) + ' ' + suffix
+ return str(n) + ' '
+
+ def get_pretty_row(self, elems, width):
+ """
+ Takes an array of elements and returns a string with those elements
+ formatted as a table row. Useful for polling modules.
+
+ :param elems: the elements to be printed
+ :param width: the width of the terminal
+ """
+ n = len(elems)
+ column_width = width / n
+
+ ret = '|'
+ for elem in elems:
+ ret += '{0:>{w}} |'.format(elem, w=column_width - 2)
+
+ return ret
+
+ def get_pretty_header(self, elems, width):
+ """
+ Like ``get_pretty_row`` but adds dashes, to be used as a table title.
+
+ :param elems: the elements to be printed
+ :param width: the width of the terminal
+ """
+ n = len(elems)
+ column_width = width / n
+
+ # dash line
+ ret = '+'
+ for i in range(0, n):
+ ret += '-' * (column_width - 1) + '+'
+ ret += '\n'
+
+ # title
+ ret += self.get_pretty_row(elems, width)
+ ret += '\n'
+
+ # dash line
+ ret += '+'
+ for i in range(0, n):
+ ret += '-' * (column_width - 1) + '+'
+ ret += '\n'
+
+ return ret
+
def get_server(self, hostname):
"""
Called by the plugin to fetch metadata about a particular hostname from