From 9f5873fe1945196ace9cb44a043078e49b7e685b Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Wed, 23 Sep 2026 09:51:35 -0400 Subject: [PATCH] Implement better indication of pending when available --- confluent_client/bin/nodeconfig | 13 +++--- confluent_client/confluent/asynclient.py | 56 +++++++++++++++++++----- confluent_client/confluent/client.py | 54 ++++++++++++++++++----- 3 files changed, 95 insertions(+), 28 deletions(-) diff --git a/confluent_client/bin/nodeconfig b/confluent_client/bin/nodeconfig index 9c84fb0e..3fa5888d 100755 --- a/confluent_client/bin/nodeconfig +++ b/confluent_client/bin/nodeconfig @@ -78,6 +78,9 @@ argparser.add_option('-m', '--maxnodes', type='int', help='Specify a maximum number of ' 'nodes to configure, ' 'prompting if over the threshold') +argparser.add_option('-p', '--pending', dest='showpending', + action='store_true', default=False, + help='Show pending changes for attributes') (options, args) = argparser.parse_args() cfgpaths = { @@ -304,21 +307,21 @@ async def main(): if options.comparedefault: continue rcode |= await client.print_attrib_path(path, session, list(queryparms[path]), - NullOpt(), queryparms[path]) + NullOpt(), queryparms[path], showpending=options.showpending) if printsys == 'all' or printextbmc or printbmc or printallbmc: if printbmc or not printextbmc: rcode |= await client.print_attrib_path( '/noderange/{0}/configuration/management_controller/extended/all'.format(noderange), - session, printbmc, options, attrprefix='bmc.') + session, printbmc, options, attrprefix='bmc.', showpending=options.showpending) if options.extra: if options.advanced: rcode |= await client.print_attrib_path( '/noderange/{0}/configuration/management_controller/extended/extra_advanced'.format(noderange), - session, printextbmc, options) + session, printextbmc, options, showpending=options.showpending) else: rcode |= await client.print_attrib_path( '/noderange/{0}/configuration/management_controller/extended/extra'.format(noderange), - session, printextbmc, options) + session, printextbmc, options, showpending=options.showpending) if printsys or options.exclude: if printsys == 'all': printsys = [] @@ -328,7 +331,7 @@ async def main(): path = '/noderange/{0}/configuration/system/advanced'.format( noderange) rcode |= await client.print_attrib_path(path, session, printsys, - options) + options, showpending=options.showpending) sys.exit(rcode) if __name__ == '__main__': diff --git a/confluent_client/confluent/asynclient.py b/confluent_client/confluent/asynclient.py index 28de349f..7ce4fafd 100644 --- a/confluent_client/confluent/asynclient.py +++ b/confluent_client/confluent/asynclient.py @@ -523,7 +523,21 @@ def _sort_attrib(k): return sortutil.naturalize_string('{}'.format(k[1]['sortid'])) return sortutil.naturalize_string(k[0]) -async def print_attrib_path(path, session, requestargs, options, rename=None, attrprefix=None): +def _is_nondefault(currattr): + if currattr.get('default', None) is None: + return False # no default specified cannot tell + if 'value' not in currattr: # can't compare if no value specified + return False + if currattr['value'] != currattr['default']: + return True + # ok, the potentially pending value is the same, but check active + if 'active' not in currattr: + return False + if currattr['active'] != currattr['default']: + return True + return False + +async def print_attrib_path(path, session, requestargs, options, rename=None, attrprefix=None, showpending=False): exitcode = 0 seenattributes = NestedDict() allnodes = set([]) @@ -551,12 +565,26 @@ async def print_attrib_path(path, session, requestargs, options, rename=None, at currattr = res['databynode'][node][attr] if show_attr(attr, requestargs, seenattributes, options, node): if 'value' in currattr: - if currattr['value'] is not None: - val = currattr['value'] - if isinstance(val, list): - val = ','.join(val) + currval = currattr.get('value', None) + if isinstance(currval, list): + currval = ','.join(currval) + activeval = currattr.get('active', currval) + if isinstance(activeval, list): + activeval = ','.join(activeval) + if activeval != currval: + if currval is None: + currval = '' + if activeval is None: + activeval = '' + if showpending: + attrout = f'{node}: {printattr}: {activeval} -> {currval}' + else: + attrout = f'{node}: {printattr}: {currval} (Pending)' + elif showpending: + continue + elif currval is not None: attrout = '{0}: {1}: {2}'.format( - node, printattr, val).strip() + node, printattr, currval).strip() else: attrout = '{0}: {1}:'.format(node, printattr) elif 'isset' in currattr: @@ -604,15 +632,19 @@ async def print_attrib_path(path, session, requestargs, options, rename=None, at except AttributeError: exclude = False if ((requestargs and not exclude) or - (currattr.get('default', None) is not None and - currattr.get('value', None) is not None and - currattr['value'] != currattr['default'])): - cval = ','.join(currattr['value']) if isinstance( + _is_nondefault(currattr)): + currval = ','.join(currattr['value']) if isinstance( currattr['value'], list) else currattr['value'] + activeval = ','.join(currattr['active']) if isinstance( + currattr.get('active'), list) else currattr.get('active') dval = ','.join(currattr['default']) if isinstance( currattr['default'], list) else currattr['default'] - cprint('{0}: {1}: {2} (Default: {3})'.format( - node, printattr, cval, dval)) + outmsg = '{0}: {1}: {2} (Default: {3}'.format( + node, printattr, currval, dval) + if 'active' in currattr: + outmsg += ', Pending change from: {0}'.format(activeval) + outmsg += ')' + cprint(outmsg) else: try: diff --git a/confluent_client/confluent/client.py b/confluent_client/confluent/client.py index f914e6b0..8cb481b1 100644 --- a/confluent_client/confluent/client.py +++ b/confluent_client/confluent/client.py @@ -473,7 +473,21 @@ def _sort_attrib(k): return sortutil.naturalize_string('{}'.format(k[1]['sortid'])) return sortutil.naturalize_string(k[0]) -def print_attrib_path(path, session, requestargs, options, rename=None, attrprefix=None): +def _is_nondefault(currattr): + if currattr.get('default', None) is None: + return False # no default specified cannot tell + if 'value' not in currattr: # can't compare if no value specified + return False + if currattr['value'] != currattr['default']: + return True + # ok, the potentially pending value is the same, but check active + if 'active' not in currattr: + return False + if currattr['active'] != currattr['default']: + return True + return False + +def print_attrib_path(path, session, requestargs, options, rename=None, attrprefix=None, showpending=False): exitcode = 0 seenattributes = NestedDict() allnodes = set([]) @@ -501,12 +515,26 @@ def print_attrib_path(path, session, requestargs, options, rename=None, attrpref currattr = res['databynode'][node][attr] if show_attr(attr, requestargs, seenattributes, options, node): if 'value' in currattr: - if currattr['value'] is not None: - val = currattr['value'] - if isinstance(val, list): - val = ','.join(val) + currval = currattr.get('value', None) + if isinstance(currval, list): + currval = ','.join(currval) + activeval = currattr.get('active', currval) + if isinstance(activeval, list): + activeval = ','.join(activeval) + if activeval != currval: + if currval is None: + currval = '' + if activeval is None: + activeval = '' + if showpending: + attrout = f'{node}: {printattr}: {activeval} -> {currval}' + else: + attrout = f'{node}: {printattr}: {currval} (Pending)' + elif showpending: + continue + elif currval is not None: attrout = '{0}: {1}: {2}'.format( - node, printattr, val).strip() + node, printattr, currval).strip() else: attrout = '{0}: {1}:'.format(node, printattr) elif 'isset' in currattr: @@ -554,15 +582,19 @@ def print_attrib_path(path, session, requestargs, options, rename=None, attrpref except AttributeError: exclude = False if ((requestargs and not exclude) or - (currattr.get('default', None) is not None and - currattr.get('value', None) is not None and - currattr['value'] != currattr['default'])): + _is_nondefault(currattr)): cval = ','.join(currattr['value']) if isinstance( currattr['value'], list) else currattr['value'] + activeval = ','.join(currattr['active']) if isinstance( + currattr.get('active'), list) else currattr.get('active') dval = ','.join(currattr['default']) if isinstance( currattr['default'], list) else currattr['default'] - cprint('{0}: {1}: {2} (Default: {3})'.format( - node, printattr, cval, dval)) + outmsg = '{0}: {1}: {2} (Default: {3}'.format( + node, printattr, cval, dval) + if 'active' in currattr: + outmsg += ', Pending change from: {0}'.format(activeval) + outmsg += ')' + cprint(outmsg) else: try: