From 9baa1f5652e90c7d6e9de07260739ed8b3b5299b Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 23 Jan 2018 13:07:59 -0500 Subject: [PATCH 1/7] Accommodate XCC firmware behavior It has been observed that a Lenovo XCC can fail to produce the appropriate attributes in the SLP data. In such a case, and only if we are in the preconfig path (which means it is a candidate for discovery), reset the XCC to try to correct the behavior. --- confluent_server/confluent/discovery/core.py | 7 ++++++- .../confluent/discovery/handlers/xcc.py | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index 9eb689dc..62337458 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -815,7 +815,12 @@ def eval_node(cfg, handler, info, nodename, manual=False): # for now, we search switch only, ideally we search cmm, smm, and # switch concurrently # do some preconfig, for example, to bring a SMM online if applicable - handler.preconfig() + errorstr = handler.preconfig() + if errorstr: + if manual: + raise exc.InvalidArgumentException(errorstr) + log.log({'error': errorstr}) + return except Exception as e: unknown_info[info['hwaddr']] = info info['discostatus'] = 'unidentified' diff --git a/confluent_server/confluent/discovery/handlers/xcc.py b/confluent_server/confluent/discovery/handlers/xcc.py index ad222489..253bb940 100644 --- a/confluent_server/confluent/discovery/handlers/xcc.py +++ b/confluent_server/confluent/discovery/handlers/xcc.py @@ -22,7 +22,24 @@ class NodeHandler(immhandler.NodeHandler): devname = 'XCC' def preconfig(self): - ff = self.info.get('attributes', {}).get('enclosure-form-factor', '') + ff = None + try: + ff = self.info['attributes']['enclosure-form-factor'] + except KeyError: + try: + # an XCC should always have that set, this is sign of + # a bug, try to reset the BMC as a workaround + ipmicmd = self._get_ipmicmd() + ipmicmd.reset_bmc() + return "XCC with address {0} did not have attributes " \ + "declared, attempting to correct with " \ + "XCC reset".format(self.ipaddr) + except pygexc.IpmiException as e: + if (e.ipmicode != 193 and + 'Unauthorized name' not in str(e) and + 'Incorrect password' not in str(e)): + # raise an issue if anything other than to be expected + raise if ff not in ('dense-computing', [u'dense-computing']): return # attempt to enable SMM From 924f679f797ddf3cdf804f4db622c4dbdf2a1b53 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 23 Jan 2018 13:27:20 -0500 Subject: [PATCH 2/7] Add ability to delete discovery entry This allows a full purge without restarting confluent. --- confluent_server/confluent/discovery/core.py | 24 +++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index 62337458..f25519ae 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -359,15 +359,10 @@ def handle_api_request(configmanager, inputdata, operation, pathcomponents): raise exc.InvalidArgumentException() rescan() return (msg.KeyValueData({'rescan': 'started'}),) - elif (operation in ('update', 'create')): + elif operation in ('update', 'create'): if 'node' not in inputdata: raise exc.InvalidArgumentException('Missing node name in input') - _, queryparms, _, _ = _parameterize_path(pathcomponents[1:]) - if 'by-mac' not in queryparms: - raise exc.InvalidArgumentException('Must target using "by-mac"') - mac = queryparms['by-mac'].replace('-', ':') - if mac not in known_info: - raise exc.NotFoundException('{0} not found'.format(mac)) + mac = _get_mac_from_query(pathcomponents) info = known_info[mac] if info['handler'] is None: raise exc.NotImplementedException( @@ -377,10 +372,24 @@ def handle_api_request(configmanager, inputdata, operation, pathcomponents): eval_node(configmanager, handler, info, inputdata['node'], manual=True) return [msg.AssignedResource(inputdata['node'])] + elif operation == 'delete': + mac = _get_mac_from_query(pathcomponents) + del known_info[mac] + return [msg.DeletedResource(mac)] raise exc.NotImplementedException( 'Unable to {0} to {1}'.format(operation, '/'.join(pathcomponents))) +def _get_mac_from_query(pathcomponents): + _, queryparms, _, _ = _parameterize_path(pathcomponents[1:]) + if 'by-mac' not in queryparms: + raise exc.InvalidArgumentException('Must target using "by-mac"') + mac = queryparms['by-mac'].replace('-', ':') + if mac not in known_info: + raise exc.NotFoundException('{0} not found'.format(mac)) + return mac + + def handle_read_api_request(pathcomponents): # TODO(jjohnson2): This should be more generalized... # odd indexes into components are 'by-'*, even indexes @@ -812,7 +821,6 @@ def get_nodename_from_enclosures(cfg, info): def eval_node(cfg, handler, info, nodename, manual=False): try: handler.probe() # unicast interrogation as possible to get more data - # for now, we search switch only, ideally we search cmm, smm, and # switch concurrently # do some preconfig, for example, to bring a SMM online if applicable errorstr = handler.preconfig() From e7aeece7f4101ed9d67147367025bb296a9ccbe5 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 23 Jan 2018 15:05:24 -0500 Subject: [PATCH 3/7] Add nodediscover `clear` Provide means of deleting discovery data, particularly to help rescan. --- confluent_client/bin/nodediscover | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/confluent_client/bin/nodediscover b/confluent_client/bin/nodediscover index 49706451..0a1d72d6 100755 --- a/confluent_client/bin/nodediscover +++ b/confluent_client/bin/nodediscover @@ -173,6 +173,13 @@ def list_discovery(options, session): for mac in list_matching_macs(options, session): print_disco(options, session, mac) +def clear_discovery(options, session): + for mac in list_matching_macs(options, session): + for res in session.delete('/discovery/by-mac/{0}'.format(mac)): + if 'deleted' in res: + print('Cleared info for {0}'.format(res['deleted'])) + else: + print(repr(res)) def list_matching_macs(options, session): path = '/discovery/' @@ -223,7 +230,7 @@ def assign_discovery(options, session): def main(): parser = optparse.OptionParser( - usage='Usage: %prog [list|assign|rescan] [options]') + usage='Usage: %prog [list|assign|rescan|clear] [options]') # -a for 'address' maybe? # order by # show state (discovered or.. @@ -253,12 +260,14 @@ def main(): help='Import bulk assignment data from given CSV file', metavar='IMPORT.CSV') (options, args) = parser.parse_args() - if len(args) == 0 or args[0] not in ('list', 'assign', 'rescan'): + if len(args) == 0 or args[0] not in ('list', 'assign', 'rescan', 'clear'): parser.print_help() sys.exit(1) session = client.Command() if args[0] == 'list': list_discovery(options, session) + if args[0] == 'clear': + clear_discovery(options, session) if args[0] == 'assign': assign_discovery(options, session) if args[0] == 'rescan': From a2163244db628d82c5b2596bf187cb6be214c018 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 23 Jan 2018 15:19:31 -0500 Subject: [PATCH 4/7] Correct indentation --- confluent_server/confluent/discovery/handlers/xcc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/confluent_server/confluent/discovery/handlers/xcc.py b/confluent_server/confluent/discovery/handlers/xcc.py index 253bb940..0e370dbb 100644 --- a/confluent_server/confluent/discovery/handlers/xcc.py +++ b/confluent_server/confluent/discovery/handlers/xcc.py @@ -38,8 +38,8 @@ class NodeHandler(immhandler.NodeHandler): if (e.ipmicode != 193 and 'Unauthorized name' not in str(e) and 'Incorrect password' not in str(e)): - # raise an issue if anything other than to be expected - raise + # raise an issue if anything other than to be expected + raise if ff not in ('dense-computing', [u'dense-computing']): return # attempt to enable SMM From 91d0c8ed7a321d60435813405d4519e9fc153fda Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 23 Jan 2018 16:09:17 -0500 Subject: [PATCH 5/7] Add flag to request discovered devices by discovery state Also refresh the manpage to reflect the current state of nodediscover command, and flesh out the discovery states there. --- confluent_client/bin/nodediscover | 7 ++++++ confluent_client/doc/man/nodediscover.ronn | 28 ++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/confluent_client/bin/nodediscover b/confluent_client/bin/nodediscover index 0a1d72d6..8bf5e03e 100755 --- a/confluent_client/bin/nodediscover +++ b/confluent_client/bin/nodediscover @@ -191,6 +191,10 @@ def list_matching_macs(options, session): path += 'by-uuid/{0}/'.format(options.uuid) if options.type: path += 'by-type/{0}/'.format(options.type) + if options.state: + if options.state == 'unknown': + options.state = 'unidentified' + path += 'by-state/{0}/'.format(options.state).lower() if options.mac: path += 'by-mac/{0}'.format(options.mac) result = list(session.read(path))[0] @@ -241,6 +245,9 @@ def main(): parser.add_option('-m', '--model', dest='model', help='Operate with nodes matching the specified model ' 'number', metavar='MODEL') + parser.add_option('-d', '--discoverystate', dest='state', + help='The discovery state of the entries (discovered, ' + 'identified, and unidentified)') parser.add_option('-s', '--serial', dest='serial', help='Operate against the system matching the specified ' 'serial number', metavar='SERIAL') diff --git a/confluent_client/doc/man/nodediscover.ronn b/confluent_client/doc/man/nodediscover.ronn index f0be14dc..70aae30d 100644 --- a/confluent_client/doc/man/nodediscover.ronn +++ b/confluent_client/doc/man/nodediscover.ronn @@ -5,7 +5,9 @@ nodediscover(8) -- List or manage confluent node discovery `nodediscover rescan` `nodediscover [options] list` -`nodeattrib [options] assign` +`nodediscover [options] assign` +`nodediscover [options] rescan` +`nodediscover [options] clear` ## DESCRIPTION @@ -22,6 +24,14 @@ data may be filtered by various parameters, as denoted in the options below. identity or, using `-i`, using a csv file to assign nodes all at once. For example, a spreadsheet of serial numbers to desired node names could be used. +**nodediscover rescan** requests the server to do an active sweep for new +devices. Generally every effort is made to passively detect devices as they +become available (as they boot or are plugged in), however sometimes an active +scan is the best approach to catch something that appears to be missing. + +**nodedsicover clear** requests the server forget about a selection of +detected device. It takes the same arguments as **nodediscover list**. + ## CSV FORMAT The CSV format used by nodediscover consists of one header describing the @@ -67,8 +77,22 @@ the nodes. address * `-t TYPE, --type=TYPE`: Operate against the system of the specified type -* `-c, --csv`: +* `-c`, ``--csv`: Use CSV formatted output +* `-d`, `--discoverystate`: + Indicate devices with a particular state. The states are: + * discovered - The device has been identified and has also had discovery + activities performed, including any relevant certificate + exchanges and deploying user and network configuration. + * identified - The device has been identified as to what node it is + supposed to be, however no active changes to the attributes + or device configuration has been performed. This is + generally discovery awaiting approval due to + discovery.policy specifying a strict security model. + * unidentified - A device has been sensed, but no node identity has been + established at all. It provides data that can be used + for nodediscover assign, as well as current IP addresses + that can be used for manual efforts as possible. * `-i IMPORT.CSV`, `--import=IMPORT.CSV`: Import bulk assignment data from given CSV file From 01dd48ccc23d1d83b32bba66b63faba350a94049 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 23 Jan 2018 16:16:47 -0500 Subject: [PATCH 6/7] Fix some man page formatting issues --- confluent_client/doc/man/nodediscover.ronn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/confluent_client/doc/man/nodediscover.ronn b/confluent_client/doc/man/nodediscover.ronn index 70aae30d..de817635 100644 --- a/confluent_client/doc/man/nodediscover.ronn +++ b/confluent_client/doc/man/nodediscover.ronn @@ -75,9 +75,9 @@ the nodes. * `-e MAC`, `--ethaddr=MAC`: Operate against the system with the specified MAC address -* `-t TYPE, --type=TYPE`: +* `-t TYPE`, `--type=TYPE`: Operate against the system of the specified type -* `-c`, ``--csv`: +* `-c`, `--csv`: Use CSV formatted output * `-d`, `--discoverystate`: Indicate devices with a particular state. The states are: From 03703250e6685c94717a76643b28a5a9ce803111 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 23 Jan 2018 16:28:07 -0500 Subject: [PATCH 7/7] Further improve formatting of the discoverystate option --- confluent_client/doc/man/nodediscover.ronn | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/confluent_client/doc/man/nodediscover.ronn b/confluent_client/doc/man/nodediscover.ronn index de817635..a4240178 100644 --- a/confluent_client/doc/man/nodediscover.ronn +++ b/confluent_client/doc/man/nodediscover.ronn @@ -79,22 +79,22 @@ the nodes. Operate against the system of the specified type * `-c`, `--csv`: Use CSV formatted output -* `-d`, `--discoverystate`: - Indicate devices with a particular state. The states are: - * discovered - The device has been identified and has also had discovery - activities performed, including any relevant certificate - exchanges and deploying user and network configuration. - * identified - The device has been identified as to what node it is - supposed to be, however no active changes to the attributes - or device configuration has been performed. This is - generally discovery awaiting approval due to - discovery.policy specifying a strict security model. - * unidentified - A device has been sensed, but no node identity has been - established at all. It provides data that can be used - for nodediscover assign, as well as current IP addresses - that can be used for manual efforts as possible. * `-i IMPORT.CSV`, `--import=IMPORT.CSV`: Import bulk assignment data from given CSV file +* `-d STATE`, `--discoverystate=STATE`: + Indicate devices with a particular state. The states are listed below +* discovered: The device has been identified and has also had discovery + activities performed, including any relevant certificate + exchanges and deploying user and network configuration. +* identified: The device has been identified as to what node it is + supposed to be, however no active changes to the attributes + or device configuration has been performed. This is + generally discovery awaiting approval due to + discovery.policy specifying a strict security model. +* unidentified: A device has been sensed, but no node identity has been + established at all. It provides data that can be used + for nodediscover assign, as well as current IP addresses + that can be used for manual efforts as possible. ## EXAMPLES