2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-04-13 16:57:59 +00:00

Implement collate command

Also adjust output to be less buffered for sake of '-w' and other
pipe commands.
This commit is contained in:
Jarrod Johnson 2017-08-09 17:08:52 -04:00
parent 87da7b62ae
commit a571faa215
6 changed files with 143 additions and 17 deletions

View File

@ -0,0 +1,76 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This is a utility to bring xcoll (plus enhancements) to confluent
# the core engine is textgroup.py, this simply provides a CLI to use
# generically
import optparse
import os
import sys
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.textgroup as tg
argparser = optparse.OptionParser(usage="Usage: <other command> | %prog [options]")
argparser.add_option('-d', '--diff', action='store_true',
help='Show what differs between most common '
'output group and others')
argparser.add_option('-w', '--watch', action='store_true',
help='Show intermediate results while running')
argparser.add_option('-s', '--skipcommon', action='store_true',
help='Do not print most common result, only non modal '
'groups, useful when combined with -d')
argparser.add_option('-c', '--count', action='store_true',
help='Also display count of nodes in a given group')
argparser.add_option('-r', '--reverse', action='store_true',
help='Reverse sort order to show biggest output group '
'last')
(options, args) = argparser.parse_args()
if sys.stdin.isatty():
argparser.print_help()
sys.exit(1)
grouped = tg.GroupedData()
def print_current():
if options.diff:
grouped.print_deviants(skipmodal=options.skipcommon, count=options.count,
reverse=options.reverse)
else:
grouped.print_all(skipmodal=options.skipcommon,
count=options.count,
reverse=options.reverse)
sys.stdout.flush()
fullline = sys.stdin.readline()
while fullline:
for line in fullline.split('\n'):
if not line:
continue
grouped.add_line(*line.split(': ', 1))
if options.watch:
sys.stdout.write('\x1b[2J\x1b[;H') # clear screen
print_current()
fullline = sys.stdin.readline()
if not options.watch:
print_current()

View File

@ -83,8 +83,10 @@ def run():
node = desc['node']
if desc['type'] == 'stdout':
sys.stdout.write('{0}: {1}'.format(node,data))
sys.stdout.flush()
else:
sys.stderr.write('{0}: {1}'.format(node, data))
sys.stderr.flush()
else:
pop = desc['popen']
ret = pop.poll()

View File

@ -146,6 +146,7 @@ def sensorpass(showout=True, appendtime=False):
'%Y-%m-%dT%H:%M:%S')
print(u'{0}: {1}:{2}'.format(
node, sensedata['name'], showval).encode('utf-8'))
sys.stdout.flush()
return resultdata

View File

@ -83,8 +83,10 @@ def run():
node = desc['node']
if desc['type'] == 'stdout':
sys.stdout.write('{0}: {1}'.format(node,data))
sys.stdout.flush()
else:
sys.stderr.write('{0}: {1}'.format(node, data))
sys.stderr.flush()
else:
pop = desc['popen']
ret = pop.poll()

View File

@ -27,6 +27,10 @@ import confluent.tlvdata as tlvdata
SO_PASSCRED = 16
def cprint(txt):
print(txt)
sys.stdout.flush()
def _parseserver(string):
if ']:' in string:
server, port = string[1:].split(']:')
@ -105,10 +109,10 @@ class Command(object):
else:
val = repr(res[node][ikey])
if self._prevkeyname and self._prevkeyname in res[node]:
print('{0}: {2}->{1}'.format(
cprint('{0}: {2}->{1}'.format(
node, val, res[node][self._prevkeyname]['value']))
else:
print('{0}: {1}'.format(node, val))
cprint('{0}: {1}'.format(node, val))
return rc
def simple_noderange_command(self, noderange, resource, input=None,
@ -133,7 +137,7 @@ class Command(object):
rc = self.handle_results(ikey, rc, res, errnodes)
return rc
except KeyboardInterrupt:
print('')
cprint('')
return 0
def simple_nodegroups_command(self, noderange, resource, input=None, key=None, **kwargs):
@ -157,7 +161,7 @@ class Command(object):
rc = self.handle_results(ikey, rc, res)
return rc
except KeyboardInterrupt:
print('')
cprint('')
return 0
def read(self, path, parameters=None):
@ -239,7 +243,7 @@ class Command(object):
"MISMATCHED CERTIFICATE DATA, ACCEPT NEW? (y/n):")
if replace not in ('y', 'Y'):
raise Exception("BAD CERTIFICATE")
print 'Adding new key for %s:%s' % (server, port)
cprint('Adding new key for %s:%s' % (server, port))
khf[hostid] = fingerprint
@ -318,7 +322,7 @@ def printattributes(session, requestargs, showtype, nodetype, noderange, options
dictout.append("{0}={1}".format(k, v))
attrout = '{0}: {1}: {2}'.format(node, attr, ','.join(map(str, dictout)))
else:
print ("CODE ERROR" + repr(attr))
cprint("CODE ERROR" + repr(attr))
if options.blame or 'broken' in currattr:
blamedata = []
@ -332,7 +336,7 @@ def printattributes(session, requestargs, showtype, nodetype, noderange, options
currattr['expression']))
if blamedata:
attrout += ' (' + ', '.join(blamedata) + ')'
print attrout
cprint(attrout)
if not exitcode:
if requestargs:
for attr in requestargs:
@ -379,8 +383,8 @@ def printgroupattributes(session, requestargs, showtype, nodetype, noderange, op
dictout.append("{0}={1}".format(k, v))
attrout = '{0}: {1}: {2}'.format(noderange, attr, ','.join(map(str, dictout)))
else:
print ("CODE ERROR" + repr(attr))
print attrout
cprint("CODE ERROR" + repr(attr))
cprint(attrout)
if not exitcode:
if requestargs:
for attr in requestargs:

View File

@ -73,10 +73,41 @@ class GroupedData(object):
else:
self.bynode[node].append(line)
def print_deviants(self, output=sys.stdout, skipmodal=True):
def print_all(self, output=sys.stdout, skipmodal=False, reverse=False,
count=False):
self.generate_byoutput()
modaloutput = None
ismodal = True
outdatalist = sorted(
self.byoutput, key=lambda x: len(self.byoutput[x]))
if not reverse:
outdatalist = reversed(outdatalist)
if reverse and skipmodal:
# if reversed, the last is biggest and should be skipped if modal
outdatalist = outdatalist[:-1]
for outdata in outdatalist:
if not reverse and skipmodal:
# If big first, this makes skipmodal skip first
skipmodal = False
continue
currout = '====================================\n'
currout += ','.join(sorted(self.byoutput[outdata]))
currout += '\n====================================\n'
if count:
currout += 'Count: {0}'.format(len(list(
self.byoutput[outdata])))
currout += '\n====================================\n'
currout += outdata
currout += '\n\n'
output.write(currout)
output.flush()
def print_deviants(self, output=sys.stdout, skipmodal=False, reverse=False,
count=False):
self.generate_byoutput()
modaloutput = None
ismodal = True
revoutput = []
for outdata in reversed(
sorted(self.byoutput, key=lambda x: len(self.byoutput[x]))):
if modaloutput is None:
@ -85,16 +116,26 @@ class GroupedData(object):
skipmodal = False
ismodal = False
continue
output.write('====================================\n')
output.write(','.join(sorted(self.byoutput[outdata])))
output.write('\n====================================\n')
currout = '====================================\n'
currout += ','.join(sorted(self.byoutput[outdata]))
currout += '\n====================================\n'
if count:
currout += 'Count: {0}'.format(len(list(
self.byoutput[outdata])))
currout += '\n====================================\n'
if ismodal:
ismodal = False
output.write(outdata)
currout += outdata
else:
output.write('\n'.join(colordiff(modaloutput.split('\n'),
outdata.split('\n'))))
output.write('\n\n')
currout += '\n'.join(colordiff(modaloutput.split('\n'),
outdata.split('\n')))
currout += '\n\n'
if reverse:
revoutput.append(currout)
else:
output.write(currout)
for currout in reversed(revoutput):
output.write(currout)
output.flush()
if __name__ == '__main__':