diff --git a/confluent_client/bin/nodeattrib b/confluent_client/bin/nodeattrib index b9a9a787..7c3c6c6c 100755 --- a/confluent_client/bin/nodeattrib +++ b/confluent_client/bin/nodeattrib @@ -55,6 +55,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) +client.check_globbing(noderange) session = client.Command() exitcode = 0 diff --git a/confluent_client/bin/nodebmcreset b/confluent_client/bin/nodebmcreset index 8d983d3a..e662ec64 100644 --- a/confluent_client/bin/nodebmcreset +++ b/confluent_client/bin/nodebmcreset @@ -38,7 +38,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) - +client.check_globbing(noderange) session = client.Command() exitcode = 0 diff --git a/confluent_client/bin/nodeboot b/confluent_client/bin/nodeboot index f8aa1adf..0c2d53bf 100755 --- a/confluent_client/bin/nodeboot +++ b/confluent_client/bin/nodeboot @@ -49,6 +49,7 @@ except IndexError: 'Usage: {0} [default|cd|network|setup|hd]\n'.format( sys.argv[0])) sys.exit(1) +client.check_globbing(noderange) bootdev = None if len(sys.argv) > 2: bootdev = sys.argv[2] diff --git a/confluent_client/bin/nodeconfig b/confluent_client/bin/nodeconfig index 62dab9fd..84d27b78 100644 --- a/confluent_client/bin/nodeconfig +++ b/confluent_client/bin/nodeconfig @@ -66,6 +66,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) +client.check_globbing(noderange) setmode = None assignment = {} queryparms = {} diff --git a/confluent_client/bin/nodedefine b/confluent_client/bin/nodedefine index b839caf0..b5184757 100644 --- a/confluent_client/bin/nodedefine +++ b/confluent_client/bin/nodedefine @@ -42,6 +42,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) +client.check_globbing(noderange) session = client.Command() exitcode = 0 attribs = {'name': noderange} diff --git a/confluent_client/bin/nodeeventlog b/confluent_client/bin/nodeeventlog index c2b094de..4614f81b 100755 --- a/confluent_client/bin/nodeeventlog +++ b/confluent_client/bin/nodeeventlog @@ -43,7 +43,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) - +client.check_globbing(noderange) deletemode = False if len(sys.argv) == 3: if sys.argv[2] == 'clear': diff --git a/confluent_client/bin/nodefirmware b/confluent_client/bin/nodefirmware index 20c1ec0d..61e7a2f9 100755 --- a/confluent_client/bin/nodefirmware +++ b/confluent_client/bin/nodefirmware @@ -81,6 +81,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) +client.check_globbing(noderange) def get_update_progress(session, url): for res in session.read(url): diff --git a/confluent_client/bin/nodegroupattrib b/confluent_client/bin/nodegroupattrib index 3ad27614..c695ad34 100755 --- a/confluent_client/bin/nodegroupattrib +++ b/confluent_client/bin/nodegroupattrib @@ -56,6 +56,7 @@ try: nodelist = '/{0}/{1}/'.format(nodetype,nodegroups) except IndexError: nodelist = '/nodegroups/' +client.check_globbing(nodegroups) session = client.Command() exitcode = 0 diff --git a/confluent_client/bin/nodehealth b/confluent_client/bin/nodehealth index 31dc21f5..5cafd960 100755 --- a/confluent_client/bin/nodehealth +++ b/confluent_client/bin/nodehealth @@ -41,6 +41,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) +client.check_globbing(noderange) def main(): diff --git a/confluent_client/bin/nodeidentify b/confluent_client/bin/nodeidentify index 0618b12e..cc86ee32 100755 --- a/confluent_client/bin/nodeidentify +++ b/confluent_client/bin/nodeidentify @@ -38,13 +38,13 @@ try: except IndexError: argparser.print_help() sys.exit(1) - +client.check_globbing(noderange) identifystate = None if len(sys.argv) > 2: identifystate = sys.argv[2] else: - argparser.print_help() - sys.exit(1) + argparser.print_help() + sys.exit(1) session = client.Command() exitcode = 0 sys.exit( diff --git a/confluent_client/bin/nodeinventory b/confluent_client/bin/nodeinventory index 926b8415..1cbb3d12 100755 --- a/confluent_client/bin/nodeinventory +++ b/confluent_client/bin/nodeinventory @@ -95,6 +95,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) +client.check_globbing(noderange) if len(args) > 1: if args[1] == 'firm': os.execlp('nodefirmware', 'nodefirmware', noderange) diff --git a/confluent_client/bin/nodelist b/confluent_client/bin/nodelist index 9892fa79..61cf4a69 100755 --- a/confluent_client/bin/nodelist +++ b/confluent_client/bin/nodelist @@ -47,6 +47,7 @@ def main(): nodelist = '/noderange/{0}/nodes/'.format(noderange) except IndexError: nodelist = '/nodes/' + client.check_globbing(noderange) session = client.Command() exitcode = 0 showtype='all' diff --git a/confluent_client/bin/nodepower b/confluent_client/bin/nodepower index c1169ea0..4eea87ae 100755 --- a/confluent_client/bin/nodepower +++ b/confluent_client/bin/nodepower @@ -40,7 +40,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) - +client.check_globbing(noderange) setstate = None if len(sys.argv) > 2: if setstate == 'softoff': diff --git a/confluent_client/bin/noderemove b/confluent_client/bin/noderemove index ffcbdcae..c4615a36 100644 --- a/confluent_client/bin/noderemove +++ b/confluent_client/bin/noderemove @@ -40,6 +40,7 @@ if len(args) != 1: argparser.print_help() sys.exit(1) noderange = args[0] +client.check_globbing(noderange) session = client.Command() exitcode = 0 for r in session.delete('/noderange/{0}'.format(noderange)): diff --git a/confluent_client/bin/nodereseat b/confluent_client/bin/nodereseat index a4c829ff..e838e42d 100644 --- a/confluent_client/bin/nodereseat +++ b/confluent_client/bin/nodereseat @@ -38,7 +38,7 @@ try: except IndexError: argparser.print_help() sys.exit(1) - +client.check_globbing(noderange) session = client.Command() exitcode = 0 diff --git a/confluent_client/bin/noderun b/confluent_client/bin/noderun index 8e380d84..816bf185 100755 --- a/confluent_client/bin/noderun +++ b/confluent_client/bin/noderun @@ -52,6 +52,7 @@ def run(): argparser.print_help() sys.exit(1) concurrentprocs = options.count + client.check_globbing(args[0]) c = client.Command() cmdstr = " ".join(args[1:]) diff --git a/confluent_client/bin/nodesensors b/confluent_client/bin/nodesensors index 7e5cc8d6..51eb9128 100755 --- a/confluent_client/bin/nodesensors +++ b/confluent_client/bin/nodesensors @@ -65,6 +65,7 @@ if options.numreadings: options.interval = 1 try: noderange = args[0] + client.check_globbing(noderange) except IndexError: argparser.print_help() sys.exit(1) @@ -79,7 +80,6 @@ for sensorgroup in args[1:]: sensors.append('sensors/hardware/all/' + sensor) if not sensors: sensors = ['sensors/hardware/all/all'] - session = client.Command() exitcode = 0 sensorheaders = {} diff --git a/confluent_client/bin/nodesetboot b/confluent_client/bin/nodesetboot index 524d30d3..7954a2bf 100755 --- a/confluent_client/bin/nodesetboot +++ b/confluent_client/bin/nodesetboot @@ -48,6 +48,7 @@ argparser.add_option('-u', '--uefi', dest='uefi', action='store_true', try: noderange = args[0] + client.check_globbing(noderange) except IndexError: argparser.print_help() sys.exit(1) diff --git a/confluent_client/bin/nodeshell b/confluent_client/bin/nodeshell index 95706c55..f80071d7 100755 --- a/confluent_client/bin/nodeshell +++ b/confluent_client/bin/nodeshell @@ -51,6 +51,7 @@ def run(): if len(args) < 2: argparser.print_help() sys.exit(1) + client.check_globbing(args[0]) concurrentprocs = options.count c = client.Command() cmdstr = " ".join(args[1:]) diff --git a/confluent_client/confluent/client.py b/confluent_client/confluent/client.py index e514b505..d3bfb66d 100644 --- a/confluent_client/confluent/client.py +++ b/confluent_client/confluent/client.py @@ -19,6 +19,7 @@ import anydbm as dbm import errno import hashlib import os +import shlex import socket import ssl import sys @@ -455,3 +456,28 @@ def updateattrib(session, updateargs, nodetype, noderange, options): exitcode = 1 sys.exit(exitcode) return exitcode + + +# So we try to prevent bad things from happening when globbing +# We tried to head this off at the shell, but the various solutions would end +# up breaking the shell in various ways (breaking pipe capability if using +# DEBUG, breaking globbing if in pipe, etc) +# Then we tried to parse the original commandline instead, however shlex isn't +# going to parse full bourne language (e.g. knowing that '|' and '>' and +# a world of other things would not be in our command line +# so finally, just make sure the noderange appears verbatim in the command line +# if we glob to something, then bash will change noderange and this should +# detect it and save the user from tragedy +def check_globbing(noderange): + rawargs = os.environ.get('CURRENT_CMDLINE', None) + if rawargs: + rawargs = shlex.split(rawargs) + for arg in rawargs: + if arg.startswith(noderange): + break + else: + sys.stderr.write( + 'Shell glob conflict detected, specified target {0} ' + 'not in command line (if bash, try set -f)' + '\n'.format(noderange)) + sys.exit(1) \ No newline at end of file diff --git a/confluent_client/confluent_env.sh b/confluent_client/confluent_env.sh index 8eed98d9..b4139b52 100644 --- a/confluent_client/confluent_env.sh +++ b/confluent_client/confluent_env.sh @@ -6,21 +6,28 @@ export MANPATH # this avoids a problem if a user does a noderange like 'n[21-33] and there is a file # in the directory like 'n3' that causes the parameter to change and target a totally # different node -alias confetty='set -f;confetty';confetty(){ command confetty "$@"; set +f;} -alias nodeattrib='set -f;nodeattrib';nodeattrib(){ command nodeattrib "$@"; set +f;} -alias nodeboot='set -f;nodeboot';nodeboot(){ command nodeboot "$@"; set +f;} -alias nodeconsole='set -f;nodeconsole';nodeconsole(){ command nodeconsole "$@"; set +f;} -alias nodedefine='set -f;nodedefine';nodedefine(){ command nodedefine "$@"; set +f;} -alias nodeeventlog='set -f;nodeeventlog';nodeeventlog(){ command nodeeventlog "$@"; set +f;} -alias nodefirmware='set -f;nodefirmware';nodefirmware(){ command nodefirmware "$@"; set +f;} -alias nodegroupattrib='set -f;nodegroupattrib';nodegroupattrib(){ command nodegroupattrib "$@"; set +f;} -alias nodehealth='set -f;nodehealth';nodehealth(){ command nodehealth "$@"; set +f;} -alias nodeidentify='set -f;nodeidentify';nodeidentify(){ command nodeidentify "$@"; set +f;} -alias nodeinventory='set -f;nodeinventory';nodeinventory(){ command nodeinventory "$@"; set +f;} -alias nodelist='set -f;nodelist';nodelist(){ command nodelist "$@"; set +f;} -alias nodepower='set -f;nodepower';nodepower(){ command nodepower "$@"; set +f;} -alias nodereseat='set -f;nodereseat';nodereseat(){ command nodereseat "$@"; set +f;} -alias noderun='set -f;noderun';noderun(){ command noderun "$@"; set +f;} -alias nodesensors='set -f;nodesensors';nodesensors(){ command nodesensors "$@"; set +f;} -alias nodesetboot='set -f;nodesetboot';nodesetboot(){ command nodesetboot "$@"; set +f;} -alias nodeshell='set -f;nodeshell';nodeshell(){ command nodeshell "$@"; set +f;} +# Unfortunately in bourne shell, we cannot reliably ensure a prepended set-f +# and an appended set +f are both run. alias seems to be the only mechanism +# that can intervene before glob expansion, but it lacks power. +# putting it into a function to append is all well and good, *except* that +# if doing something like 'nodepower compute|grep' causes set -f to execute +# in current shell, and the function to be in a subshell and leaves globbing +# disabled in the parent shell. Instead, store the current command in a +# variable and use that to check for misglobbed noderanges, which was the goal +alias nodeattrib='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeattrib' +alias nodeboot='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeboot' +alias nodeconsole='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeconsole' +alias nodedefine='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodedefine' +alias nodeeventlog='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeeventlog' +alias nodefirmware='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodefirmware' +alias nodegroupattrib='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodegroupattrib' +alias nodehealth='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodehealth' +alias nodeidentify='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeidentify' +alias nodeinventory='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeinventory' +alias nodelist='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodelist' +alias nodepower='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodepower' +alias nodereseat='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodereseat' +alias noderun='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; noderun' +alias nodesensors='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodesensors' +alias nodesetboot='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodesetboot' +alias nodeshell='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeshell'