diff --git a/confluent_client/bin/nodeattrib b/confluent_client/bin/nodeattrib new file mode 100644 index 00000000..e0120be4 --- /dev/null +++ b/confluent_client/bin/nodeattrib @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# 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. + +__author__ = 'alin37' + +import optparse +import os +import sys + +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 + +def attrrequested(attr, attrlist, seenattributes): + for candidate in attrlist: + truename = candidate + if candidate.startswith('hm'): + candidate = candidate.replace('hm', 'hardwaremanagement', 1) + if candidate == attr: + seenattributes.add(truename) + return True + elif '.' not in candidate and attr.startswith(candidate + '.'): + seenattributes.add(truename) + return True + return False +argparser = optparse.OptionParser( + usage='''\n %prog [options] noderange [list of attributes] \ + \n %prog [options] noderange attribute1=value1,attribute2=value,... + \n ''') +argparser.add_option('-b', '--blame', action='store_true', + help='Show information about how attributes inherited') +argparser.add_option('-c', '--clear', action='store_true', + help='Clear variables') +(options, args) = argparser.parse_args() + +showtype = 'current' +requestargs=None +try: + noderange = args[0] + nodelist = '/noderange/{0}/nodes/'.format(noderange) +except IndexError: + nodelist = '/nodes/' +session = client.Command() +exitcode = 0 + + +#Sets attributes +if len(args) > 1: + #clears attribute + if options.clear: + targpath = '/noderange/{0}/attributes/all'.format(noderange) + keydata = {} + for attrib in args[1:]: + keydata[attrib] = None + for res in session.update(targpath, keydata): + if 'error' in res: + if 'errorcode' in res: + exitcode = res['errorcode'] + sys.stderr.write('Error: ' + res['error'] + '\n') + sys.exit(exitcode) + else: + if args[1] == 'all': + showtype = 'all' + elif args[1] == 'current': + showtype = 'current' + elif "=" in args[1]: + try: + if len(args[1:]) > 1: + for val in args[1:]: + val = val.split('=') + exitcode=session.simple_noderange_command(noderange, 'attributes/all'.format(noderange), val[1], val[0]) + else: + val=args[1].split('=') + exitcode=session.simple_noderange_command(noderange, 'attributes/all'.format(noderange),val[1],val[0]) + except: + sys.stderr.write('Error: {0} not a valid expression\n'.format(str (args[1:]))) + exitcode = 1 + sys.exit(exitcode) + else: + requestargs = args[1:] + +# Lists all attributes +if len(args) > 0: + seenattributes = set([]) + for res in session.read('/noderange/{0}/attributes/{1}'.format(noderange,showtype)): + if 'error' in res: + print "found error" + sys.stderr.write(res['error'] + '\n') + exitcode = 1 + continue + for node in res['databynode']: + for attr in res['databynode'][node]: + seenattributes.add(attr) + currattr = res['databynode'][node][attr] + if requestargs is None or attrrequested(attr, args[1:], seenattributes): + if 'value' in currattr: + if currattr['value'] is not None: + attrout = '{0}: {1}: {2}'.format( + node, attr, currattr['value']) + else: + attrout = '{0}: {1}:'.format(node, attr) + elif 'isset' in currattr: + if currattr['isset']: + attrout = '{0}: {1}: ********'.format(node, attr) + else: + attrout = '{0}: {1}:'.format(node, attr) + elif 'broken' in currattr: + attrout = '{0}: {1}: *ERROR* BROKEN EXPRESSION: ' \ + '{2}'.format(node, attr, + currattr['broken']) + if options.blame or 'broken' in currattr: + blamedata = [] + if 'inheritedfrom' in currattr: + blamedata.append('inherited from group {0}'.format( + currattr['inheritedfrom'] + )) + if 'expression' in currattr: + blamedata.append( + 'derived from expression "{0}"'.format( + currattr['expression'])) + if blamedata: + attrout += ' (' + ', '.join(blamedata) + ')' + print attrout + + if not exitcode: + if requestargs: + for attr in args[1:]: + if attr not in seenattributes: + sys.stderr.write('Error: {0} not a valid attribute\n'.format(attr)) + exitcode = 1 +else: + for res in session.read(nodelist): + if 'error' in res: + sys.stderr.write(res['error'] + '\n') + exitcode = 1 + else: + print res['item']['href'].replace('/', '') +sys.exit(exitcode) \ No newline at end of file diff --git a/confluent_client/doc/man/nodeattrib.ronn b/confluent_client/doc/man/nodeattrib.ronn new file mode 100644 index 00000000..dc330b0c --- /dev/null +++ b/confluent_client/doc/man/nodeattrib.ronn @@ -0,0 +1,75 @@ +nodeattrib(1) -- List or change confluent nodes attributes +========================================================= + +## SYNOPSIS + +`nodeattrib` `noderange` [ current | all ] +`nodeattrib` `noderange` [-b] [...] +`nodeattrib` `noderange` [ ...] +`nodeattrib` `noderange` [-c] [ ...] + +## DESCRIPTION + +**nodeattrib** queries the confluent server to get information about nodes. In +the simplest form, it simply takes the given noderange(5) and lists the +matching nodes, one line at a time. + +If a list of node attribute names are given, the value of those are also +displayed. If `-b` is specified, it will also display information on +how inherited and expression based attributes are defined. There is more +information on node attributes in nodeattributes(5) man page. +If `-c` is specified, this will set the nodeattribute to a null valid. +This is different from setting the value to an empty string. + +## OPTIONS + +* `-b`, `--blame`: + Annotate inherited and expression based attributes to show their base value. +* `-c`, `--clear`: + Clear given nodeattributes since '' is not the same as empty + +## EXAMPLES +* Listing matching nodes of a simple noderange: + `# nodeattrib n1-n2` + `n1`: console.method: ipmi + `n1`: hardwaremanagement.manager: 172.30.3.1 + `n2`: console.method: ipmi + `n2`: hardwaremanagement.manager: 172.30.3.2 + +* Getting an attribute of nodes matching a noderange: + `# nodeattrib n1,n2 hardwaremanagement.manager` + `n1: hardwaremanagement.manager: 172.30.3.1` + `n2: hardwaremanagement.manager: 172.30.3.2` + +* Getting a group of attributes while determining what group defines them: + `# nodeattrib n1,n2 hardwaremanagement --blame` + `n1: hardwaremanagement.manager: 172.30.3.1` + `n1: hardwaremanagement.method: ipmi (inherited from group everything)` + `n1: hardwaremanagement.switch: r8e1` + `n1: hardwaremanagement.switchport: 14` + `n2: hardwaremanagement.manager: 172.30.3.2` + `n2: hardwaremanagement.method: ipmi (inherited from group everything)` + `n2: hardwaremanagement.switch: r8e1` + `n2: hardwaremanagement.switchport: 2` + + * Listing matching nodes of a simple noderange that are set: + `# nodeattrib n1-n2 current` + `n1`: console.method: ipmi + `n1`: hardwaremanagement.manager: 172.30.3.1 + `n2`: console.method: ipmi + `n2`: hardwaremanagement.manager: 172.30.3.2 + + * Change attribute on nodes of a simple noderange: + `# nodeattrib n1-n2 console.method=serial` + `n1`: console.method: serial + `n1`: hardwaremanagement.manager: 172.30.3.1 + `n2`: console.method: serial + `n2`: hardwaremanagement.manager: 172.30.3.2 + + * Clear attribute on nodes of a simple noderange, if you want to retain the variable set the attribute to "": + `# nodeattrib n1-n2 -c console.method` + `# nodeattrib n1-n2 console.method` + Error: console.logging not a valid attribute + + +