2019-09-23 14:59:00 +00:00
|
|
|
#!/usr/bin/python2
|
2016-05-11 21:03:05 +00:00
|
|
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
|
2017-01-06 18:28:28 +00:00
|
|
|
# Copyright 2016-2017 Lenovo
|
2016-05-11 21:03:05 +00:00
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
|
2017-08-16 13:57:57 +00:00
|
|
|
import codecs
|
2018-05-11 17:49:54 +00:00
|
|
|
import json
|
2017-01-06 18:28:28 +00:00
|
|
|
import optparse
|
2016-05-11 21:03:05 +00:00
|
|
|
import os
|
2017-08-08 15:49:50 +00:00
|
|
|
import re
|
2017-06-20 18:56:24 +00:00
|
|
|
import signal
|
2016-05-11 21:03:05 +00:00
|
|
|
import sys
|
2017-06-20 18:56:24 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2016-05-11 21:03:05 +00:00
|
|
|
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.client as client
|
|
|
|
|
2019-06-28 12:51:57 +00:00
|
|
|
if sys.version_info[0] < 3:
|
|
|
|
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
|
2017-08-16 13:57:57 +00:00
|
|
|
|
2017-08-08 15:49:50 +00:00
|
|
|
filters = []
|
|
|
|
|
2016-05-11 21:03:05 +00:00
|
|
|
|
2016-05-12 13:19:30 +00:00
|
|
|
def pretty(text):
|
|
|
|
if text == 'pcislot':
|
|
|
|
return 'PCI slot'
|
|
|
|
if text == 'partnumber':
|
|
|
|
return 'part number'
|
|
|
|
return text
|
|
|
|
|
2016-05-11 21:03:05 +00:00
|
|
|
def print_mem_info(node, prefix, meminfo):
|
|
|
|
memdescfmt = '{0}GB PC'
|
|
|
|
if meminfo['memory_type'] == 'DDR3 SDRAM':
|
|
|
|
memdescfmt += '3-{1} '
|
2019-03-28 17:37:13 +00:00
|
|
|
elif 'DDR4' in meminfo['memory_type']:
|
2016-05-11 21:03:05 +00:00
|
|
|
memdescfmt += '4-{1} '
|
2021-09-22 14:50:32 +00:00
|
|
|
elif 'DCPMM' in meminfo['memory_type']:
|
2021-09-22 14:52:29 +00:00
|
|
|
memdescfmt = '{0}GB {1} '
|
2021-09-22 14:50:32 +00:00
|
|
|
meminfo['module_type'] = 'DCPMM'
|
2017-12-07 21:51:55 +00:00
|
|
|
else:
|
2017-12-07 21:54:35 +00:00
|
|
|
print('{0}: {1}: Unrecognized Memory'.format(node, prefix))
|
2017-10-18 13:51:31 +00:00
|
|
|
return
|
2019-03-28 17:37:13 +00:00
|
|
|
if meminfo.get('ecc', False):
|
2016-05-11 21:03:05 +00:00
|
|
|
memdescfmt += 'ECC '
|
2017-10-18 13:51:31 +00:00
|
|
|
capacity = meminfo['capacity_mb'] / 1024
|
2019-04-15 15:08:56 +00:00
|
|
|
modtype = meminfo.get('module_type', None)
|
|
|
|
if modtype:
|
|
|
|
memdescfmt += modtype
|
2016-05-11 21:03:05 +00:00
|
|
|
memdesc = memdescfmt.format(capacity, meminfo['speed'])
|
|
|
|
print('{0}: {1} description: {2}'.format(node, prefix, memdesc))
|
|
|
|
print('{0}: {1} manufacturer: {2}'.format(
|
|
|
|
node, prefix, meminfo['manufacturer']))
|
|
|
|
print('{0}: {1} model: {2}'.format(node, prefix, meminfo['model']))
|
|
|
|
print('{0}: {1} serial number: {2}'.format(node, prefix,
|
|
|
|
meminfo['serial']))
|
2019-03-28 17:37:13 +00:00
|
|
|
if 'manufacture_date' in meminfo:
|
|
|
|
print('{0}: {1} manufacture date: {2}'.format(node, prefix,
|
|
|
|
meminfo['manufacture_date']))
|
|
|
|
print('{0}: {1} manufacture location: {2}'.format(
|
|
|
|
node, prefix, meminfo['manufacture_location']))
|
2016-05-11 21:03:05 +00:00
|
|
|
|
2016-05-12 14:25:35 +00:00
|
|
|
exitcode = 0
|
|
|
|
|
|
|
|
def printerror(res, node=None):
|
|
|
|
global exitcode
|
|
|
|
if 'errorcode' in res:
|
|
|
|
exitcode = res['errorcode']
|
|
|
|
if 'error' in res:
|
|
|
|
if node:
|
|
|
|
sys.stderr.write('{0}: {1}\n'.format(node, res['error']))
|
|
|
|
else:
|
|
|
|
sys.stderr.write('{0}\n'.format(res['error']))
|
|
|
|
if 'errorcode' not in res:
|
|
|
|
exitcode = 1
|
|
|
|
|
2016-05-11 21:03:05 +00:00
|
|
|
|
2017-08-08 15:49:50 +00:00
|
|
|
url = '/noderange/{0}/inventory/hardware/all/all'
|
2018-09-07 15:49:13 +00:00
|
|
|
usedprefixes = set([])
|
2017-08-08 15:49:50 +00:00
|
|
|
|
2017-08-08 19:45:53 +00:00
|
|
|
argparser = optparse.OptionParser(
|
|
|
|
usage="Usage: %prog <noderange> [serial|model|uuid|mac]")
|
2018-05-11 17:49:54 +00:00
|
|
|
argparser.add_option('-j', '--json', action='store_true', help='Output JSON')
|
2023-01-13 17:29:36 +00:00
|
|
|
argparser.add_option('-s', '--store', action='store_true', help='Store serial, model, and uuid into id.serial, id.model, and id.uuid')
|
2017-01-06 18:28:28 +00:00
|
|
|
(options, args) = argparser.parse_args()
|
2016-05-11 21:03:05 +00:00
|
|
|
try:
|
2018-05-11 17:49:54 +00:00
|
|
|
noderange = args[0]
|
2016-05-11 21:03:05 +00:00
|
|
|
except IndexError:
|
2017-01-06 18:28:28 +00:00
|
|
|
argparser.print_help()
|
2016-05-11 21:03:05 +00:00
|
|
|
sys.exit(1)
|
2017-11-13 16:49:40 +00:00
|
|
|
client.check_globbing(noderange)
|
2017-08-08 15:49:50 +00:00
|
|
|
if len(args) > 1:
|
|
|
|
if args[1] == 'firm':
|
|
|
|
os.execlp('nodefirmware', 'nodefirmware', noderange)
|
|
|
|
else:
|
|
|
|
url = '/noderange/{0}/inventory/hardware/all/system'
|
|
|
|
for arg in args:
|
|
|
|
for arg in arg.split(','):
|
|
|
|
if arg == 'serial':
|
|
|
|
filters.append(re.compile('serial number'))
|
|
|
|
elif arg == 'model':
|
|
|
|
filters.append(re.compile('^model'))
|
|
|
|
filters.append(re.compile('product name'))
|
|
|
|
elif arg == 'uuid':
|
|
|
|
filters.append(re.compile('uuid'))
|
|
|
|
elif arg == 'mac':
|
|
|
|
filters.append(re.compile('mac address'))
|
|
|
|
url = '/noderange/{0}/inventory/hardware/all/all'
|
2016-05-11 21:03:05 +00:00
|
|
|
try:
|
2018-05-11 17:49:54 +00:00
|
|
|
if options.json:
|
|
|
|
databynode = {}
|
2023-01-13 17:29:36 +00:00
|
|
|
if options.store and len(args) <= 1:
|
|
|
|
url = '/noderange/{0}/inventory/hardware/all/system'
|
|
|
|
pushattribs = {}
|
2016-05-11 21:03:05 +00:00
|
|
|
session = client.Command()
|
2017-08-08 15:49:50 +00:00
|
|
|
for res in session.read(url.format(noderange)):
|
2016-05-12 14:25:35 +00:00
|
|
|
printerror(res)
|
|
|
|
if 'databynode' not in res:
|
|
|
|
continue
|
2016-05-11 21:03:05 +00:00
|
|
|
for node in res['databynode']:
|
2023-01-13 17:29:36 +00:00
|
|
|
if options.store and node not in pushattribs:
|
|
|
|
pushattribs[node] = {}
|
2016-05-12 14:25:35 +00:00
|
|
|
printerror(res['databynode'][node], node)
|
|
|
|
if 'inventory' not in res['databynode'][node]:
|
|
|
|
continue
|
2016-05-11 21:03:05 +00:00
|
|
|
for inv in res['databynode'][node]['inventory']:
|
|
|
|
prefix = inv['name']
|
2023-01-13 17:29:36 +00:00
|
|
|
if options.store and prefix == 'System':
|
|
|
|
currinfo = inv.get('information', {})
|
|
|
|
curruuid = currinfo.get('UUID', '')
|
|
|
|
if curruuid:
|
|
|
|
curruuid = curruuid.lower()
|
|
|
|
pushattribs[node]['id.uuid'] = curruuid
|
|
|
|
currserial = currinfo.get('Serial Number', '')
|
|
|
|
if currserial:
|
|
|
|
currserial = currserial.strip()
|
|
|
|
pushattribs[node]['id.serial'] = currserial
|
|
|
|
currmodelnum = currinfo.get('Model', '')
|
|
|
|
if currmodelnum:
|
|
|
|
currmodelnum = currmodelnum.strip()
|
|
|
|
pushattribs[node]['id.model'] = currmodelnum
|
2018-09-07 15:49:13 +00:00
|
|
|
idx = 2
|
2018-09-10 19:09:50 +00:00
|
|
|
while (node, prefix) in usedprefixes:
|
2018-09-07 15:49:13 +00:00
|
|
|
prefix = '{0} {1}'.format(inv['name'], idx)
|
|
|
|
idx += 1
|
2018-09-10 19:09:50 +00:00
|
|
|
usedprefixes.add((node, prefix))
|
2016-05-11 21:03:05 +00:00
|
|
|
if not inv['present']:
|
2018-05-11 18:24:47 +00:00
|
|
|
if not filters:
|
|
|
|
if options.json:
|
|
|
|
if node not in databynode:
|
|
|
|
databynode[node] = {}
|
|
|
|
databynode[node][prefix] = inv
|
2023-01-13 17:29:36 +00:00
|
|
|
elif not options.store:
|
2019-06-28 12:51:57 +00:00
|
|
|
print('{0}: {1}: Not Present'.format(node, prefix))
|
2016-05-11 21:03:05 +00:00
|
|
|
continue
|
|
|
|
info = inv['information']
|
|
|
|
info.pop('board_extra', None)
|
|
|
|
info.pop('oem_parser', None)
|
|
|
|
info.pop('chassis_extra', None)
|
|
|
|
info.pop('product_extra', None)
|
|
|
|
if 'memory_type' in info:
|
2017-08-08 15:49:50 +00:00
|
|
|
if not filters:
|
2018-05-11 18:18:04 +00:00
|
|
|
if options.json:
|
|
|
|
if node not in databynode:
|
|
|
|
databynode[node] = {}
|
|
|
|
databynode[node][prefix] = inv
|
|
|
|
continue
|
2017-08-08 15:49:50 +00:00
|
|
|
print_mem_info(node, prefix, info)
|
2016-05-11 21:03:05 +00:00
|
|
|
continue
|
|
|
|
for datum in info:
|
2017-08-08 15:49:50 +00:00
|
|
|
if filters:
|
|
|
|
for filter in filters:
|
|
|
|
if filter.match(datum.lower()):
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
continue
|
2016-05-11 21:03:05 +00:00
|
|
|
if info[datum] is None:
|
|
|
|
continue
|
2018-05-11 18:18:04 +00:00
|
|
|
if options.json:
|
|
|
|
if node not in databynode:
|
|
|
|
databynode[node] = {}
|
|
|
|
databynode[node][prefix] = inv
|
|
|
|
break
|
2023-01-13 17:29:36 +00:00
|
|
|
elif not options.store:
|
|
|
|
print(u'{0}: {1} {2}: {3}'.format(node, prefix,
|
|
|
|
pretty(datum),
|
|
|
|
info[datum]))
|
2018-05-11 17:49:54 +00:00
|
|
|
if options.json:
|
|
|
|
print(json.dumps(databynode, sort_keys=True, indent=4,
|
|
|
|
separators=(',', ': ')))
|
2023-01-13 17:29:36 +00:00
|
|
|
if pushattribs:
|
|
|
|
for node in pushattribs:
|
|
|
|
for rsp in session.update('/nodes/{0}/attributes/current'.format(node), pushattribs[node]):
|
|
|
|
if 'error' in rsp:
|
|
|
|
sys.stderr.write(rsp['error'] + '\n')
|
2016-05-11 21:03:05 +00:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
print('')
|
2018-05-11 17:49:54 +00:00
|
|
|
sys.exit(exitcode)
|