From e32d3cf4cc0267f0ed33f0db22f6821742b5455c Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 10 May 2019 10:34:56 -0400 Subject: [PATCH 1/5] Add auto-index determination to stats This allows it to auto-skip over units, for example. --- confluent_client/bin/stats | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/confluent_client/bin/stats b/confluent_client/bin/stats index 1329f240..c6629c3a 100755 --- a/confluent_client/bin/stats +++ b/confluent_client/bin/stats @@ -83,11 +83,25 @@ args = aparser.parse_args(sys.argv[1:]) plotdata = [] data = sys.stdin.readline() nodebydatum = {} +idx = args.c - 1 +autoidx = False while data: node = None if ':' in data: node, data = data.split(':', 1) - datum = float(data.split()[args.c - 1]) + if idx == -1: + while not autoidx: + try: + datum = float(data.split()[idx]) + except ValueError: + idx -= 1 + continue + except IndexError: + sys.stderr.write('Unable to identify a numerical column\n') + sys.exit(1) + autoidx = True + else: + datum = float(data.split()[idx]) if node: if datum in nodebydatum: nodebydatum[datum].add(node) @@ -100,7 +114,7 @@ if args.g or args.o or args.s: n, bins = plot(args.g, args.o, plotdata, bins=args.b) if args.t: n, bins = textplot(plotdata, bins=args.b) -print('Samples: {5} Min: {3} Median: {0} Mean: {1} Max: {4} StandardDeviation: {2}'.format(np.median(plotdata), np.mean(plotdata), np.std(plotdata), np.min(plotdata), np.max(plotdata), len(plotdata))) +print('Samples: {5} Min: {3} Median: {0} Mean: {1} Max: {4} StandardDeviation: {2} Sum: {6}'.format(np.median(plotdata), np.mean(plotdata), np.std(plotdata), np.min(plotdata), np.max(plotdata), len(plotdata), np.sum(plotdata))) if args.v and n is not None and nodebydatum: print('') currbin = bins[0] From c042583a6449373f21d5a5a16be301bb263dd068 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 10 May 2019 11:08:12 -0400 Subject: [PATCH 2/5] Add support for CSV formatted data Presume CSV semantics for input. --- confluent_client/bin/stats | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/confluent_client/bin/stats b/confluent_client/bin/stats index c6629c3a..39463f90 100755 --- a/confluent_client/bin/stats +++ b/confluent_client/bin/stats @@ -16,6 +16,7 @@ # limitations under the License. import argparse +import csv import fcntl import io import numpy as np @@ -73,7 +74,9 @@ def textplot(plotdata, bins): histogram = False aparser = argparse.ArgumentParser(description='Quick access to common statistics') aparser.add_argument('-c', type=int, default=0, help='Column number to analyze (default is last column)') -aparser.add_argument('-s', default=False, action='store_true', help='Output histogram in sixel format') +aparser.add_argument('-d', default=None, help='Value used to separate columns') +aparser.add_argument('-x', default=False, action='store_true', help='Output histogram in sixel format') +aparser.add_argument('-s', default=0, help='Number of header lines to skip before processing') aparser.add_argument('-g', default=False, action='store_true', help='Open histogram in separate graphical window') aparser.add_argument('-o', default=None, help='Output histogram to the specified filename in PNG format') aparser.add_argument('-t', default=False, action='store_true', help='Output a histogram in text format') @@ -81,18 +84,35 @@ aparser.add_argument('-v', default=False, action='store_true', help='Attempt to aparser.add_argument('-b', type=int, default=10, help='Number of bins to use in histogram (default is 10)') args = aparser.parse_args(sys.argv[1:]) plotdata = [] -data = sys.stdin.readline() +headlines = int(args.s) +while headlines >= 0: + data = sys.stdin.readline() + headlines -= 1 +if args.d: + delimiter = args.d +else: + if '\t' in data: + delimiter = '\t' + elif ' ' in data: + delimiter = ' ' + elif ',' in data: + delimiter = ',' + else: + delimiter = ' ' # handle single column +data = list(csv.reader([data], delimiter=delimiter))[0] nodebydatum = {} idx = args.c - 1 autoidx = False while data: node = None - if ':' in data: - node, data = data.split(':', 1) - if idx == -1: + if ':' in data[0]: + node, data[0] = data[0].split(':', 1) + else: + node = data[0] + if idx == -1 and not autoidx: while not autoidx: try: - datum = float(data.split()[idx]) + datum = float(data[idx]) except ValueError: idx -= 1 continue @@ -101,7 +121,7 @@ while data: sys.exit(1) autoidx = True else: - datum = float(data.split()[idx]) + datum = float(data[idx]) if node: if datum in nodebydatum: nodebydatum[datum].add(node) @@ -109,8 +129,9 @@ while data: nodebydatum[datum] = set([node]) plotdata.append(datum) data = sys.stdin.readline() + data = list(csv.reader([data], delimiter=delimiter))[0] n = None -if args.g or args.o or args.s: +if args.g or args.o or args.x: n, bins = plot(args.g, args.o, plotdata, bins=args.b) if args.t: n, bins = textplot(plotdata, bins=args.b) From cd2361b80b125d8e128d6479b5eede8da9aed72d Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 10 May 2019 13:11:04 -0400 Subject: [PATCH 3/5] Fix nodediscover clear for operators Operators should be allowed to delete discovery data. --- confluent_server/confluent/auth.py | 1 + 1 file changed, 1 insertion(+) diff --git a/confluent_server/confluent/auth.py b/confluent_server/confluent/auth.py index 7605fc30..eadcd3a1 100644 --- a/confluent_server/confluent/auth.py +++ b/confluent_server/confluent/auth.py @@ -68,6 +68,7 @@ _allowedbyrole = { '/nodes/*/shell/sessions*', ], 'delete': [ + '/discovery/*', '/node*/*/events/hardware/log', ], }, From cc5a5c9972ae16a7eae4d6806ef9ebe9d2d1eade Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 10 May 2019 13:15:19 -0400 Subject: [PATCH 4/5] Fix operator add and delete of nodes This permits operators to run nodedefine and noderemove. --- confluent_server/confluent/auth.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/confluent_server/confluent/auth.py b/confluent_server/confluent/auth.py index eadcd3a1..da15f491 100644 --- a/confluent_server/confluent/auth.py +++ b/confluent_server/confluent/auth.py @@ -45,6 +45,8 @@ _allowedbyrole = { 'Operator': { 'retrieve': ['*'], 'create': [ + '/noderange/', + '/nodes/', '/node*/media/uploads/', '/node*/inventory/firmware/updates/*', '/node*/suppport/servicedata*', @@ -69,7 +71,7 @@ _allowedbyrole = { ], 'delete': [ '/discovery/*', - '/node*/*/events/hardware/log', + '/node*', ], }, 'Monitor': { From ad828e609d5c986656d4826145e1984fb6ded45c Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 10 May 2019 14:34:39 -0400 Subject: [PATCH 5/5] Reduce bad default login tries For an SD530 XCC, we would incur 4 attempts at default: -To pre-config enable SMM, we try once -Due to pyghmi auto-degrade, try again as oper -Then during the actual config phase, try again -Again, try again as oper Now with pyghmi opt-out, we will force to try only as admin, eliminating the second try. The SD530 code will now mark that the default creds failed so that the config phase will know to skip that. --- .../confluent/discovery/handlers/bmc.py | 15 +++++++++++++-- .../confluent/discovery/handlers/xcc.py | 2 ++ .../confluent/plugins/hardwaremanagement/ipmi.py | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/confluent_server/confluent/discovery/handlers/bmc.py b/confluent_server/confluent/discovery/handlers/bmc.py index 389b429a..dc783f8b 100644 --- a/confluent_server/confluent/discovery/handlers/bmc.py +++ b/confluent_server/confluent/discovery/handlers/bmc.py @@ -32,10 +32,21 @@ DEFAULT_PASS = 'PASSW0RD' class NodeHandler(generic.NodeHandler): - def _get_ipmicmd(self, user=DEFAULT_USER, password=DEFAULT_PASS): - return ipmicommand.Command(self.ipaddr, user, password) + def _get_ipmicmd(self, user=None, password=None): + priv = None + if user is None or password is None: + if self.trieddefault: + raise pygexc.IpmiException() + priv = 4 # manually indicate priv to avoid double-attempt + if user is None: + user = DEFAULT_USER + if password is None: + password = DEFAULT_PASS + return ipmicommand.Command(self.ipaddr, user, password, + privlevel=priv, keepalive=False) def __init__(self, info, configmanager): + self.trieddefault = None super(NodeHandler, self).__init__(info, configmanager) def probe(self): diff --git a/confluent_server/confluent/discovery/handlers/xcc.py b/confluent_server/confluent/discovery/handlers/xcc.py index 1c7280e6..1e222627 100644 --- a/confluent_server/confluent/discovery/handlers/xcc.py +++ b/confluent_server/confluent/discovery/handlers/xcc.py @@ -33,6 +33,7 @@ class NodeHandler(immhandler.NodeHandler): ff = self.info.get('attributes', {}).get('enclosure-form-factor', '') if ff not in ('dense-computing', [u'dense-computing']): return + self.trieddefault = None # Reset state on a preconfig attempt # attempt to enable SMM #it's normal to get a 'not supported' (193) for systems without an SMM ipmicmd = None @@ -44,6 +45,7 @@ class NodeHandler(immhandler.NodeHandler): 'Incorrect password' not in str(e)): # raise an issue if anything other than to be expected raise + self.trieddefault = True #TODO: decide how to clean out if important #as it stands, this can step on itself #if ipmicmd: diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 8d0e610d..3e7533a6 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -171,6 +171,7 @@ class IpmiCommandWrapper(ipmicommand.Command): self.node = node self._inhealth = False self._lasthealth = None + kwargs['keepalive'] = False self._attribwatcher = cfm.watch_attributes( (node,), ('secret.hardwaremanagementuser', 'collective.manager', 'secret.hardwaremanagementpassword', 'secret.ipmikg',