mirror of
https://github.com/xcat2/confluent.git
synced 2024-11-22 09:32:21 +00:00
0c4cb49c20
This provides access to 'extra' settings. Mainly intended to avoid slowing down nodeconfig with IMM attributes that most people don't want anyway.
303 lines
11 KiB
Python
Executable File
303 lines
11 KiB
Python
Executable File
#!/usr/bin/python2
|
|
# 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.
|
|
|
|
|
|
import os
|
|
import signal
|
|
import optparse
|
|
import shlex
|
|
import sys
|
|
|
|
try:
|
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
except AttributeError:
|
|
pass
|
|
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
|
|
|
|
class NullOpt(object):
|
|
blame = None
|
|
clear = None
|
|
|
|
|
|
def bailout(msg, code=1):
|
|
sys.stderr.write(msg + '\n')
|
|
sys.exit(code)
|
|
|
|
|
|
argparser = optparse.OptionParser(usage="Usage: %prog [options] noderange [option|option=value]")
|
|
argparser.add_option('-c', '--comparedefault', dest='comparedefault',
|
|
action='store_true', default=False,
|
|
help='Compare given settings to default or list settings '
|
|
'that are non default')
|
|
argparser.add_option('-b', '--batch', dest='batch', metavar='settings.batch',
|
|
default=False, help='Provide settings in a batch file')
|
|
argparser.add_option('-d', '--detail', dest='detail',
|
|
action='store_true', default=False,
|
|
help='Provide verbose information as available, such as '
|
|
'help text and possible valid values')
|
|
argparser.add_option('-e', '--extra', dest='extra',
|
|
action='store_true', default=False,
|
|
help='Access extra configuration. Extra configuration is generally '
|
|
'reserved for unpopular or redundant options that may be slow to '
|
|
'read. Notably the IMM category on Lenovo settings is considered '
|
|
'to be extra configuration')
|
|
argparser.add_option('-x', '--exclude', dest='exclude',
|
|
action='store_true', default=False,
|
|
help='Treat positional arguments as items to not '
|
|
'examine, compare, or restore default')
|
|
argparser.add_option('-a', '--advanced', dest='advanced',
|
|
action='store_true', default=False,
|
|
help='Include advanced settings, which are normally not '
|
|
'intended to be used without direction from the '
|
|
'relevant server vendor.')
|
|
argparser.add_option('-r', '--restoredefault', default=False,
|
|
dest='restoredefault', metavar="COMPONENT",
|
|
help='Restore the configuration of the node '
|
|
'to factory default for given component. '
|
|
'Currently only uefi is supported')
|
|
argparser.add_option('-m', '--maxnodes', type='int',
|
|
help='Specify a maximum number of '
|
|
'nodes to configure, '
|
|
'prompting if over the threshold')
|
|
(options, args) = argparser.parse_args()
|
|
|
|
cfgpaths = {
|
|
'bmc.ipv4_address': (
|
|
'configuration/management_controller/net_interfaces/management',
|
|
'ipv4_address'),
|
|
'bmc.ipv4_method': (
|
|
'configuration/management_controller/net_interfaces/management',
|
|
'ipv4_configuration'),
|
|
'bmc.ipv4_gateway': (
|
|
'configuration/management_controller/net_interfaces/management',
|
|
'ipv4_gateway'),
|
|
'bmc.hostname': (
|
|
'configuration/management_controller/hostname', 'hostname'),
|
|
}
|
|
|
|
autodeps = {
|
|
'bmc.ipv4_address': (('bmc.ipv4_method', 'static'),)
|
|
}
|
|
|
|
try:
|
|
noderange = args[0]
|
|
except IndexError:
|
|
argparser.print_help()
|
|
sys.exit(1)
|
|
client.check_globbing(noderange)
|
|
setmode = None
|
|
assignment = {}
|
|
queryparms = {}
|
|
printsys = []
|
|
printbmc = []
|
|
printallbmc = False
|
|
setsys = {}
|
|
forceset = False
|
|
needval = None
|
|
|
|
if len(args) == 1 or options.exclude:
|
|
if not options.exclude:
|
|
printsys = 'all'
|
|
for candidate in cfgpaths:
|
|
path, attrib = cfgpaths[candidate]
|
|
path = '/noderange/{0}/{1}'.format(noderange, path)
|
|
if path not in queryparms:
|
|
queryparms[path] = {}
|
|
queryparms[path][attrib] = candidate
|
|
|
|
|
|
def _assign_value():
|
|
if key not in cfgpaths:
|
|
setsys[key] = value
|
|
for depkey, depval in autodeps.get(key, []):
|
|
assignment[depkey] = depval
|
|
assignment[key] = value
|
|
|
|
|
|
def parse_config_line(arguments):
|
|
global setmode, printallbmc, forceset, key, value, needval, candidate, path, attrib
|
|
for param in arguments:
|
|
if param == 'show':
|
|
continue # forgive muscle memory of pasu users
|
|
if param == 'set':
|
|
setmode = True
|
|
forceset = True
|
|
continue
|
|
if needval:
|
|
key = needval
|
|
needval = None
|
|
value = param
|
|
_assign_value()
|
|
continue
|
|
if '=' in param or param[-1] == ':' or forceset:
|
|
if setmode is None:
|
|
setmode = True
|
|
if setmode != True:
|
|
bailout('Cannot do set and query in same command')
|
|
if '=' in param:
|
|
key, _, value = param.partition('=')
|
|
_assign_value()
|
|
elif param[-1] == ':':
|
|
needval = param[:-1]
|
|
else:
|
|
needval = param
|
|
else:
|
|
if setmode is None:
|
|
setmode = False
|
|
if setmode != False:
|
|
bailout('Cannot do set and query in same command')
|
|
if '.' not in param:
|
|
if param == 'bmc':
|
|
printallbmc = True
|
|
matchedparms = False
|
|
for candidate in cfgpaths:
|
|
if candidate.startswith('{0}.'.format(param)):
|
|
matchedparms = True
|
|
if not options.exclude:
|
|
path, attrib = cfgpaths[candidate]
|
|
path = '/noderange/{0}/{1}'.format(noderange, path)
|
|
if path not in queryparms:
|
|
queryparms[path] = {}
|
|
queryparms[path][attrib] = candidate
|
|
else:
|
|
try:
|
|
del queryparms[path]
|
|
except KeyError:
|
|
pass
|
|
if not matchedparms:
|
|
printsys.append(param)
|
|
elif param not in cfgpaths:
|
|
if param.startswith('bmc.'):
|
|
printbmc.append(param.replace('bmc.', ''))
|
|
else:
|
|
printsys.append(param)
|
|
else:
|
|
path, attrib = cfgpaths[param]
|
|
path = '/noderange/{0}/{1}'.format(noderange, path)
|
|
if path not in queryparms:
|
|
queryparms[path] = {}
|
|
queryparms[path][attrib] = param
|
|
|
|
if options.batch:
|
|
printsys = []
|
|
argfile = open(options.batch, 'r')
|
|
argset = argfile.readline()
|
|
while argset:
|
|
try:
|
|
argset = argset[:argset.index('#')]
|
|
except ValueError:
|
|
pass
|
|
argset = argset.strip()
|
|
if argset:
|
|
parse_config_line(shlex.split(argset))
|
|
argset = argfile.readline()
|
|
else:
|
|
parse_config_line(args[1:])
|
|
session = client.Command()
|
|
rcode = 0
|
|
if options.restoredefault:
|
|
session.stop_if_noderange_over(noderange, options.maxnodes)
|
|
if options.restoredefault.lower() in (
|
|
'sys', 'system', 'uefi', 'bios'):
|
|
for fr in session.update(
|
|
'/noderange/{0}/configuration/system/clear'.format(noderange),
|
|
{'clear': True}):
|
|
rcode |= client.printerror(fr)
|
|
sys.exit(rcode)
|
|
elif options.restoredefault.lower() in (
|
|
'bmc', 'imm', 'xcc'):
|
|
for fr in session.update(
|
|
'/noderange/{0}/configuration/management_controller/clear'.format(noderange),
|
|
{'clear': True}):
|
|
rcode |= client.printerror(fr)
|
|
sys.exit(rcode)
|
|
else:
|
|
sys.stderr.write(
|
|
'Unrecognized component to restore defaults: {0}\n'.format(
|
|
options.restoredefault))
|
|
sys.exit(1)
|
|
if setmode:
|
|
session.stop_if_noderange_over(noderange, options.maxnodes)
|
|
if options.exclude:
|
|
sys.stderr.write('Cannot use exclude and assign at the same time\n')
|
|
sys.exit(1)
|
|
updatebypath = {}
|
|
attrnamebypath = {}
|
|
for key in assignment:
|
|
if key not in cfgpaths:
|
|
if key.startswith('bmc.'):
|
|
path = 'configuration/management_controller/extended/all'
|
|
attrib = key.replace('bmc.', '')
|
|
else:
|
|
path = 'configuration/system/all'
|
|
attrib = key
|
|
else:
|
|
path, attrib = cfgpaths[key]
|
|
if path not in updatebypath:
|
|
updatebypath[path] = {}
|
|
attrnamebypath[path] = {}
|
|
updatebypath[path][attrib] = assignment[key]
|
|
attrnamebypath[path][attrib] = key
|
|
# well, we want to expand things..
|
|
# check ipv4, if requested change method to static
|
|
for path in updatebypath:
|
|
for fr in session.update('/noderange/{0}/{1}'.format(noderange, path),
|
|
updatebypath[path]):
|
|
rcode |= client.printerror(fr)
|
|
for node in fr.get('databynode', []):
|
|
r = fr['databynode'][node]
|
|
rcode |= client.printerror(r, node)
|
|
if 'value' not in r:
|
|
continue
|
|
keyval = r['value']
|
|
key, val = keyval.split('=')
|
|
if key in attrnamebypath[path]:
|
|
key = attrnamebypath[path][key]
|
|
print('{0}: {1}: {2}'.format(node, key, val))
|
|
else:
|
|
for path in queryparms:
|
|
if options.comparedefault:
|
|
continue
|
|
rc = client.print_attrib_path(path, session, list(queryparms[path]),
|
|
NullOpt(), queryparms[path])
|
|
if rc:
|
|
sys.exit(rc)
|
|
if printbmc or printallbmc:
|
|
rcode = client.print_attrib_path(
|
|
'/noderange/{0}/configuration/management_controller/extended/all'.format(noderange),
|
|
session, printbmc, options, attrprefix='bmc.')
|
|
if options.extra:
|
|
rcode |= client.print_attrib_path(
|
|
'/noderange/{0}/configuration/management_controller/extended/extra'.format(noderange),
|
|
session, printbmc, options)
|
|
if printsys or options.exclude:
|
|
if printsys == 'all':
|
|
printsys = []
|
|
if (options.comparedefault or printsys == []) and not options.advanced:
|
|
path = '/noderange/{0}/configuration/system/all'.format(noderange)
|
|
else:
|
|
path = '/noderange/{0}/configuration/system/advanced'.format(
|
|
noderange)
|
|
rcode = client.print_attrib_path(path, session, printsys,
|
|
options)
|
|
sys.exit(rcode)
|