mirror of
https://github.com/xcat2/confluent.git
synced 2024-12-25 12:41:39 +00:00
620263db3e
This uses the client maxnodes check to double check. Useful for clients that want to sanity check unexpectedly large numbers of nodes.
294 lines
11 KiB
Python
Executable File
294 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('-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 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)
|