From 38228ebc9b5730069325aa8a2e0eaa13be33ce0a Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 4 Sep 2018 11:09:26 -0400 Subject: [PATCH 01/11] Fix the prompting code changes --- confluent_client/bin/nodegroupattrib | 1 + confluent_client/confluent/client.py | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/confluent_client/bin/nodegroupattrib b/confluent_client/bin/nodegroupattrib index b066b284..bba961ed 100755 --- a/confluent_client/bin/nodegroupattrib +++ b/confluent_client/bin/nodegroupattrib @@ -17,6 +17,7 @@ __author__ = 'alin37' +from getpass import getpass import optparse import os import signal diff --git a/confluent_client/confluent/client.py b/confluent_client/confluent/client.py index b8c6c6f9..bc5cd4fe 100644 --- a/confluent_client/confluent/client.py +++ b/confluent_client/confluent/client.py @@ -530,13 +530,11 @@ def updateattrib(session, updateargs, nodetype, noderange, options, dictassign=N elif dictassign: for key in dictassign: if nodetype == 'nodegroups': - exitcode = session.simp_nodegroups_command(noderange, - 'attributes/all', - dictassign[key], key) + exitcode = session.simple_nodegroups_command( + noderange, 'attributes/all', dictassign[key], key) else: - exitcode = session.simp_nodegroups_command(noderange, - 'attributes/all', - dictassign[key], key) + exitcode = session.simple_noderange_command( + noderange, 'attributes/all', dictassign[key], key) else: if "=" in updateargs[1]: try: From 2a8d61ecf631332b283338d9fd7c811e67a07f45 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 6 Sep 2018 16:10:48 -0400 Subject: [PATCH 02/11] Enrich the less than useful 'Adapter' inventory items We can provide DNS provided info about such generic items to make them look more fleshed out. --- .../plugins/hardwaremanagement/ipmi.py | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 05c77050..aad59c5a 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -25,6 +25,7 @@ import eventlet.green.threading as threading import eventlet.greenpool as greenpool import eventlet.queue as queue import eventlet.support.greendns +from fnmatch import fnmatch import pyghmi.constants as pygconstants import pyghmi.exceptions as pygexc console = eventlet.import_patched('pyghmi.ipmi.console') @@ -32,6 +33,37 @@ ipmicommand = eventlet.import_patched('pyghmi.ipmi.command') import socket import ssl +pci_cache = {} + +def get_dns_txt(qstring): + return eventlet.support.greendns.resolver.query( + qstring, 'TXT')[0].strings[0].replace('i=', '') + +def get_pci_text_from_ids(subdevice, subvendor, device, vendor): + fqpi = '{0}.{1}.{2}.{3}'.format(subdevice, subvendor, device, vendor) + if fqpi in pci_cache: + return pci_cache[fqpi] + vendorstr = None + try: + vendorstr = get_dns_txt('{0}.pci.id.ucw.cz'.format(subvendor)) + except Exception: + try: + vendorstr = get_dns_txt('{0}.pci.id.ucw.cz'.format(vendor)) + except Exception: + pass + devstr = None + try: + devstr = get_dns_txt(fqpi + '.pci.id.ucw.cz') + except Exception: + try: + devstr = get_dns_txt('{0}.{1}.pci.id.ucw.cz'.format( + device, vendor)) + except Exception: + pass + if vendorstr and devstr: + pci_cache[fqpi] = vendorstr, devstr + return vendorstr, devstr + # There is something not right with the RLocks used in pyghmi when # eventlet comes into play. It seems like sometimes on acquire, @@ -841,7 +873,7 @@ class IpmiHandler(object): sanitize_invdata(invdata[1]) newinf = {'present': True, 'information': invdata[1]} newinf['name'] = invdata[0] - invitems.append(newinf) + self.add_invitem(invitems, newinf) else: self.make_inventory_map() compname = self.invmap.get(component, None) @@ -855,7 +887,7 @@ class IpmiHandler(object): sanitize_invdata(invdata) newinf = {'present': True, 'information': invdata} newinf['name'] = compname - invitems.append(newinf) + self.add_invitem(invitems, newinf) except ssl.SSLEOFError: errorneeded = msg.ConfluentNodeError( self.node, 'Unable to communicate with the https server on ' @@ -872,6 +904,20 @@ class IpmiHandler(object): if errorneeded: self.output.put(errorneeded) + def add_invitem(self, invitems, newinf): + if fnmatch(newinf['name'], 'Adapter ??:??:??'): + myinf = newinf.get('information', {}) + sdid = myinf.get('PCI Subsystem Device ID', None) + svid = myinf.get('PCI Subsystem Vendor ID', None) + did = myinf.get('PCI Device ID', None) + vid = myinf.get('PCI Vendor ID', None) + vstr, dstr = get_pci_text_from_ids(sdid, svid, did, vid) + if vstr: + newinf['information']['PCI Vendor'] = vstr + if dstr: + newinf['name'] = dstr + invitems.append(newinf) + def handle_sensors(self): if self.element[-1] == '': self.element = self.element[:-1] From b3bf6929dfc1f4827dd224762b43508b25bed0fc Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 6 Sep 2018 16:16:26 -0400 Subject: [PATCH 03/11] Add replacement logic for another generic variant In IMM, PCeGen3 x8 and similar is also possible. --- confluent_server/confluent/plugins/hardwaremanagement/ipmi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index aad59c5a..1cd70e23 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -905,7 +905,8 @@ class IpmiHandler(object): self.output.put(errorneeded) def add_invitem(self, invitems, newinf): - if fnmatch(newinf['name'], 'Adapter ??:??:??'): + if fnmatch(newinf['name'], 'Adapter ??:??:??') or fnmatch( + newinf['name'], 'PCIeGen? x*'): myinf = newinf.get('information', {}) sdid = myinf.get('PCI Subsystem Device ID', None) svid = myinf.get('PCI Subsystem Vendor ID', None) From 47a53a51e4bb625e28232cb8f792f2053b2e0b64 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 7 Sep 2018 11:16:09 -0400 Subject: [PATCH 04/11] Fix non-unique name for similar inventory items. --- .../confluent/plugins/hardwaremanagement/ipmi.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 1cd70e23..2052cc6e 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -410,6 +410,7 @@ persistent_ipmicmds = {} class IpmiHandler(object): def __init__(self, operation, node, element, cfd, inputdata, cfg, output): self.sensormap = {} + self.usedlabels = {} self.invmap = {} self.output = output self.sensorcategory = None @@ -916,7 +917,12 @@ class IpmiHandler(object): if vstr: newinf['information']['PCI Vendor'] = vstr if dstr: - newinf['name'] = dstr + newname = dstr + instance = 1 + while newname in self.usednames: + instance += 1 + newname = dstr + ' {1}'.format(instance) + newinf['name'] = newname invitems.append(newinf) def handle_sensors(self): From 34b7abcb2d689e8245bf1745066f763903aef651 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 7 Sep 2018 11:27:43 -0400 Subject: [PATCH 05/11] Change systemd unit to not have PIDFile systemctl restart *always* prints a worrying message with pidfile. --- confluent_server/systemd/confluent.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confluent_server/systemd/confluent.service b/confluent_server/systemd/confluent.service index 7f1dcec1..7a6f8fea 100644 --- a/confluent_server/systemd/confluent.service +++ b/confluent_server/systemd/confluent.service @@ -4,7 +4,7 @@ Description=Confluent hardware manager [Service] Type=forking -PIDFile=/var/run/confluent/pid +#PIDFile=/var/run/confluent/pid ExecStart=/opt/confluent/bin/confluent ExecStop=/opt/confluent/bin/confetty shutdown / Restart=on-failure From e7be24d4780b5deb46d3911fdd6b7010bcfb77a8 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 7 Sep 2018 11:44:01 -0400 Subject: [PATCH 06/11] Revert "Fix non-unique name for similar inventory items." This reverts commit 47a53a51e4bb625e28232cb8f792f2053b2e0b64. --- .../confluent/plugins/hardwaremanagement/ipmi.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 2052cc6e..1cd70e23 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -410,7 +410,6 @@ persistent_ipmicmds = {} class IpmiHandler(object): def __init__(self, operation, node, element, cfd, inputdata, cfg, output): self.sensormap = {} - self.usedlabels = {} self.invmap = {} self.output = output self.sensorcategory = None @@ -917,12 +916,7 @@ class IpmiHandler(object): if vstr: newinf['information']['PCI Vendor'] = vstr if dstr: - newname = dstr - instance = 1 - while newname in self.usednames: - instance += 1 - newname = dstr + ' {1}'.format(instance) - newinf['name'] = newname + newinf['name'] = dstr invitems.append(newinf) def handle_sensors(self): From 07532e2a3f0cad84a2e1807d8d50220e5d8fc1ca Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 7 Sep 2018 11:49:13 -0400 Subject: [PATCH 07/11] Have nodeinventory disambiguate duplicate labels. The data is still there for putting identical cards together, but the prefix is unique, particularly important for json mode. --- confluent_client/bin/nodeinventory | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/confluent_client/bin/nodeinventory b/confluent_client/bin/nodeinventory index 9c8a6f2b..a2d23bb0 100755 --- a/confluent_client/bin/nodeinventory +++ b/confluent_client/bin/nodeinventory @@ -87,6 +87,7 @@ def printerror(res, node=None): url = '/noderange/{0}/inventory/hardware/all/all' +usedprefixes = set([]) argparser = optparse.OptionParser( usage="Usage: %prog [serial|model|uuid|mac]") @@ -129,6 +130,11 @@ try: continue for inv in res['databynode'][node]['inventory']: prefix = inv['name'] + idx = 2 + while prefix in usedprefixes: + prefix = '{0} {1}'.format(inv['name'], idx) + idx += 1 + usedprefixes.add(prefix) if not inv['present']: if not filters: if options.json: From d04be19ae52968e3e9019c8109701641a5db3e61 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 7 Sep 2018 14:37:02 -0400 Subject: [PATCH 08/11] Preferentially use a 'name' subfield as 'name' Pyghmi now may suggest a more useful name. The component name is unique, but 'name' can indicate the common name of things with multiple instances. --- .../plugins/hardwaremanagement/ipmi.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 1cd70e23..11c30e29 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -19,6 +19,7 @@ import confluent.firmwaremanager as firmwaremanager import confluent.interface.console as conapi import confluent.messages as msg import confluent.util as util +import copy import eventlet import eventlet.event import eventlet.green.threading as threading @@ -868,11 +869,13 @@ class IpmiHandler(object): if component == 'all': for invdata in self.ipmicmd.get_inventory(): if invdata[1] is None: - newinf = {'present': False, 'information': None} + newinf = {'present': False, 'information': None, + 'name': invdata[0]} + else: sanitize_invdata(invdata[1]) newinf = {'present': True, 'information': invdata[1]} - newinf['name'] = invdata[0] + newinf['name'] = invdata[1].get('name', invdata[0]) self.add_invitem(invitems, newinf) else: self.make_inventory_map() @@ -882,11 +885,12 @@ class IpmiHandler(object): return invdata = self.ipmicmd.get_inventory_of_component(compname) if invdata is None: - newinf = {'present': False, 'information': None} + newinf = {'present': False, 'information': None, + 'name': compname} else: sanitize_invdata(invdata) - newinf = {'present': True, 'information': invdata} - newinf['name'] = compname + newinf = {'present': True, 'information': invdata, + 'name': invdata.get('name', compname)} self.add_invitem(invitems, newinf) except ssl.SSLEOFError: errorneeded = msg.ConfluentNodeError( @@ -896,7 +900,7 @@ class IpmiHandler(object): except exc.PubkeyInvalid: errorneeded = msg.ConfluentNodeError( self.node, - 'Extended information unavailable, mismatch detected between ' + 'Extended information unakvailable, mismatch detected between ' 'target certificate fingerprint and ' 'pubkeys.tls_hardwaremanager attribute') newinvdata = {'inventory': invitems} @@ -905,6 +909,9 @@ class IpmiHandler(object): self.output.put(errorneeded) def add_invitem(self, invitems, newinf): + if newinf.get('information', None) and 'name' in newinf['information']: + newinf = copy.deepcopy(newinf) + del newinf['information']['name'] if fnmatch(newinf['name'], 'Adapter ??:??:??') or fnmatch( newinf['name'], 'PCIeGen? x*'): myinf = newinf.get('information', {}) From db5f861dc597d6ee8c8572fafab92533da83c5c1 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 10 Sep 2018 14:25:04 -0400 Subject: [PATCH 09/11] Fix introduced typo in error message --- confluent_server/confluent/plugins/hardwaremanagement/ipmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py index 11c30e29..f6b2b32a 100644 --- a/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py +++ b/confluent_server/confluent/plugins/hardwaremanagement/ipmi.py @@ -900,7 +900,7 @@ class IpmiHandler(object): except exc.PubkeyInvalid: errorneeded = msg.ConfluentNodeError( self.node, - 'Extended information unakvailable, mismatch detected between ' + 'Extended information unavailable, mismatch detected between ' 'target certificate fingerprint and ' 'pubkeys.tls_hardwaremanager attribute') newinvdata = {'inventory': invitems} From 7c550bd68e6cca1cc270bdaf0311c67a3e2b28d3 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 10 Sep 2018 15:09:50 -0400 Subject: [PATCH 10/11] Fix prefix fixup It was not allowing same label across nodes. --- confluent_client/bin/nodeinventory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/confluent_client/bin/nodeinventory b/confluent_client/bin/nodeinventory index a2d23bb0..a87eabfe 100755 --- a/confluent_client/bin/nodeinventory +++ b/confluent_client/bin/nodeinventory @@ -131,10 +131,10 @@ try: for inv in res['databynode'][node]['inventory']: prefix = inv['name'] idx = 2 - while prefix in usedprefixes: + while (node, prefix) in usedprefixes: prefix = '{0} {1}'.format(inv['name'], idx) idx += 1 - usedprefixes.add(prefix) + usedprefixes.add((node, prefix)) if not inv['present']: if not filters: if options.json: From f601032a66cc54387bf817eea7a947d84439b3ae Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 14 Sep 2018 16:50:20 -0400 Subject: [PATCH 11/11] Fix everything group missing if nodegroup created before node everything group was not making it to disk unless a node is created first. Correctly mark the need for disk sync to fix. --- confluent_server/confluent/config/configmanager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/confluent_server/confluent/config/configmanager.py b/confluent_server/confluent/config/configmanager.py index a1431ad9..d5e7d1e5 100644 --- a/confluent_server/confluent/config/configmanager.py +++ b/confluent_server/confluent/config/configmanager.py @@ -965,6 +965,7 @@ class ConfigManager(object): self._cfgstore = _cfgstore['main'] if 'nodegroups' not in self._cfgstore: self._cfgstore['nodegroups'] = {'everything': {'nodes': set()}} + _mark_dirtykey('nodegroups', 'everything', self.tenant) self._bg_sync_to_file() if 'nodes' not in self._cfgstore: self._cfgstore['nodes'] = {} @@ -980,6 +981,7 @@ class ConfigManager(object): self._cfgstore = _cfgstore['tenant'][tenant] if 'nodegroups' not in self._cfgstore: self._cfgstore['nodegroups'] = {'everything': {}} + _mark_dirtykey('nodegroups', 'everything', self.tenant) if 'nodes' not in self._cfgstore: self._cfgstore['nodes'] = {} self._bg_sync_to_file()