Clean up getdata and json filtering code

Can now add/remove links
This commit is contained in:
Rob Pearce 2022-01-02 20:58:57 +11:00
parent dc49f26251
commit bb4d15e508
1 changed files with 391 additions and 223 deletions

614
gnscli.sh
View File

@ -1,5 +1,6 @@
#!/bin/bash #!/bin/bash
# addepactionusage "links" "add" "ahost aport zhost zport'
# better cinfirmation when removing a link
# clean up action output # clean up action output
# add node issue with menu when type isnt specified # add node issue with menu when type isnt specified
@ -314,7 +315,6 @@ function debug() {
if [[ $VERBOSE -eq 1 ]]; then if [[ $VERBOSE -eq 1 ]]; then
if [[ $force -eq 1 ]]; then if [[ $force -eq 1 ]]; then
echo -e "${PURPLE}${BOLD}${FUNCNAME[1]}(): ${PLAIN}${PURPLE}$*${PLAIN}" >/dev/stderr echo -e "${PURPLE}${BOLD}${FUNCNAME[1]}(): ${PLAIN}${PURPLE}$*${PLAIN}" >/dev/stderr
echo -e "${PURPLE}${BOLD}${FUNCNAME[1]}(): ${PLAIN}${PURPLE}$*${PLAIN}" >/tmp/a
else else
echo -e "${PURPLE}${BOLD}${FUNCNAME[1]}(): ${PLAIN}${PURPLE}$*${PLAIN}" 1>&2 echo -e "${PURPLE}${BOLD}${FUNCNAME[1]}(): ${PLAIN}${PURPLE}$*${PLAIN}" 1>&2
fi fi
@ -965,9 +965,15 @@ debug -f "arglist - obname: $obname"
debug -f "arglist - extrainfo : $extrainfo" debug -f "arglist - extrainfo : $extrainfo"
debug -f "arglist: remaining opts: $opts" debug -f "arglist: remaining opts: $opts"
if [[ $actionname == "add" || $actionname == "mv" ]]; then if [[ $actionname == "add" || $actionname == "mv" ]]; then
curldata=$(makejson "$extrainfo") if [[ -n $RAWJSONPOSTDATA ]]; then
curldata="${RAWJSONPOSTDATA}"
else
curldata=$(makejson "$extrainfo")
fi
fi fi
RAWJSONPOSTDATA=""
# special case # special case
if [[ $actionname == "connect" ]]; then if [[ $actionname == "connect" ]]; then
local locidx local locidx
@ -1012,7 +1018,9 @@ debug -f "arglist: remaining opts: $opts"
debug -f "curldata: ${curldata}" debug -f "curldata: ${curldata}"
if [[ $action == "add" || $action == "mv" ]]; then if [[ $action == "add" || $action == "mv" ]]; then
# note: "obuuid" is empty when adding a builtin node like VPCS # note: "obuuid" is empty in some cases, eg:
# adding a builtin node like VPCS
# adding a link
curlres=$(runcurldatapost "$loc" "$api_endpoint" "$obuuid" "$curldata" ) curlres=$(runcurldatapost "$loc" "$api_endpoint" "$obuuid" "$curldata" )
crv=$? crv=$?
else else
@ -1040,6 +1048,55 @@ debug -f "arglist: remaining opts: $opts"
return $rv return $rv
} }
# uses globals jqscrjpt, jqfilter, awkscript
function apply_filters() { # retvar wantquotes [f][s][a]
local retvar which data wantquotes rawopt qstr
retvar="$1"
wantquotes="${2:-0}"
debug "wantquotes is $wantquotes"
if [[ $wantquotes -eq 0 ]]; then
rawopt="-r"
qstr="without quotes (jq -r)"
elif [[ $wantquotes -eq -1 ]]; then
rawopt="-r"
qstr="REALLY without quotes (jq -r | sed_remove_quotes)"
else
rawopt=""
qstr="with quotes"
fi
[[ -z $retvar ]] && return 1
which="${3:-sfa}"
eval "data=\"\$$retvar\""
debug "applying: $which $qstr"
debug " wantquotes is $wantquotes"
debug " jqfilter is $jqfilter"
debug " jqscript is $jqscript"
debug " awkscript is $awkscript"
if [[ $which == *f* && -n $jqfilter ]]; then
#debug "$retvar pre jqfilter is $data"
echo "$data" >/tmp/a
data=$(echo "$data" | jq $rawopt "$jqfilter" 2>/dev/null)
if [[ $wantquotes -eq -1 ]]; then
data=$(echo "$data" | tr -d '"')
fi
#debug "$retvar post jqfilter is $data"
fi
if [[ $which == *s* && -n $jqscript ]]; then
debug "jqscript contents: $(cat $jqscript)"
debug "$retvar pre jqscript is $data"
data=$(echo "$data" | jq $rawopt -f "$jqscript")
debug "$retvar post jqscript is $data"
fi
if [[ $which == *a* && -n $awkscript ]]; then
debug "$retvar pre awkscript is $data"
data=$(echo "$data" | awk -f "$awkscript")
fi
eval $retvar=\"\$data\"
return 0
}
function getdata_loc() { # getdata_loc syd|etc api_endpoint [options] function getdata_loc() { # getdata_loc syd|etc api_endpoint [options]
local thisgrid thisauthdom thisurl thisauthstr curlres loc u p local thisgrid thisauthdom thisurl thisauthstr curlres loc u p
local api_endpoint jq_obj opts opts_arr deffield epidx r1 r2 rv local api_endpoint jq_obj opts opts_arr deffield epidx r1 r2 rv
@ -1065,55 +1122,20 @@ debug "options: ${opts}"
debug "outmode is $outmode" debug "outmode is $outmode"
debug "jqscript is $jqscript" debug "jqscript is $jqscript"
debug "jqfilter is $jqfilter" debug "jqfilter is $jqfilter"
debug "awkscript is $awkscript"
if [[ $outmode == "raw" ]]; then if [[ $outmode == "raw" ]]; then
[[ ! -z $curlres ]] && echo "$curlres" || rv=2
elif [[ $outmode == "verbose" ]]; then
#if [[ $locnum -eq 1 ]]; then
# # bold+underline the heading, and store in a temp file
# echo "$curlres" | jq -r "$jqfilter" 2>/dev/null | tr -d '"' | awk '{ if (NR == 1) { printf "\033[1m\033[4m" $0 "\033[0m\n" } }' >$HEADINGFILE
#fi
r1="$curlres" r1="$curlres"
if [[ ! -z $jqfilter ]]; then # only apply jqfilter
debug "jqfilter is $jqfilter" apply_filters r1 $QUOTES f
debug "r1 pre jqfilter is $r1" [[ -n $r1 ]] && echo "$r1" || rv=2
r1=$(echo "$r1" | jq -r "$jqfilter" 2>/dev/null | tr -d '"') elif [[ $outmode == "verbose" ]]; then
debug "r1 post jqfilter is $r1" r1="$curlres"
fi apply_filters r1 $REALLYNOQUOTES
#if [[ ! -z $regexpfilter ]]; then [[ -n $r1 ]] && echo "$r1" || rv=2
# [[ $VERBOSE -eq 1 ]] && debug "r1 pre regexpfilter is $r1"
# r1=$(echo "$r1" | awk -v filter="$regexpfilter" '(NR==1){ print } (NR !=1 && (match($0,filter))) { print }')
#fi
if [[ ! -z $jqscript ]]; then
debug "jqscript is $jqscript"
debug "jqscript contents: $(cat $jqscript)"
debug "r1 pre jqscript is $r1"
echo "$r1" >/tmp/out
r1=$(echo "$r1" | jq -rf "$jqscript")
fi
[[ ! -z $r1 ]] && echo "$r1" || rv=2
else # namesonly else # namesonly
r1=$(echo "$curlres") r1=$(echo "$curlres")
if [[ ! -z $jqfilter ]]; then apply_filters r1
debug "jqfilter is $jqfilter"
debug "r1 pre jqfilter is $r1"
r1=$(echo "$r1" | jq -r "$jqfilter" 2>/dev/null)
debug "r1 post jqfilter is $r1"
fi
if [[ ! -z $jqscript ]]; then
debug "jqscript is $jqscript"
debug "r1 pre jqscript is $r1"
r1=$(echo "$r1" | jq -rf "$jqscript")
fi
# if [[ ! -z $regexpfilter ]]; then
# debug "r1 pre regexpfilter is $r1"
# r1=$(echo "$r1" | awk -v filter="$regexpfilter" '(NR==1){ print } (NR !=1 && (match($0,filter))) { print }')
# fi
if [[ ! -z $awkscript ]]; then
debug "r1 pre awkscript is $r1"
r1=$(echo "$r1" | awk -f "$awkscript")
fi
debug "semi-final r1 is [$r1]" debug "semi-final r1 is [$r1]"
if [[ $cmd == "list" ]]; then if [[ $cmd == "list" ]]; then
debug "Global cmd is $GLOBALCMD" debug "Global cmd is $GLOBALCMD"
@ -1121,10 +1143,8 @@ echo "$r1" >/tmp/out
# ie. we end up with each line being: # ie. we end up with each line being:
# location,object,object_uuid # location,object,object_uuid
#r1=$(echo "$r1" | egrep -v "^$" | sed "s/^/$loc,$thisgrid,/")
r1=$(echo "$r1" | egrep -v "^$" | sed "s/^/$loc,/") r1=$(echo "$r1" | egrep -v "^$" | sed "s/^/$loc,/")
else else
#r1=$(echo "$r1" | egrep -v "^$" | sed "s/^/$(echo -e "$BOLD")\[$thisgrid\] $(echo -e "$PLAIN")/")
r1=$(echo "$r1" | egrep -v "^$") r1=$(echo "$r1" | egrep -v "^$")
fi fi
fi fi
@ -1132,7 +1152,6 @@ echo "$r1" >/tmp/out
[[ -n $r1 ]] && echo "$r1" | sed 's/__END__://' || rv=2 [[ -n $r1 ]] && echo "$r1" | sed 's/__END__://' || rv=2
fi fi
#echo "$curlres" | jq -r "$jqfilter" | sed "s/^/$(echo -e "$BOLD")\[$thisgrid\] $(echo -e "$PLAIN")/"
debug "about to exit with code $rv" debug "about to exit with code $rv"
return $rv return $rv
} }
@ -1195,7 +1214,7 @@ function getbasefilter() { # epidx [regexp_filter]
filterarg="$*" filterarg="$*"
[[ $filterarg == "*" ]] && filterarg=".*" [[ $filterarg == "*" ]] && filterarg=".*"
[[ -n "$*" ]] && refilter="select(.name|test(\"^$*$\"))" || refilter="." [[ -n "$*" ]] && refilter="select(.${ep_defaultfield[$epidx]}|test(\"^$*$\"))" || refilter="."
IFS='#' read -r -a titles <<< "${ep_titles[$epidx]}" IFS='#' read -r -a titles <<< "${ep_titles[$epidx]}"
IFS='#' read -r -a fields <<< "${ep_fields[$epidx]}" IFS='#' read -r -a fields <<< "${ep_fields[$epidx]}"
@ -1293,7 +1312,7 @@ debug "repl is $repl"
debug "table after repl [\n$table]" debug "table after repl [\n$table]"
# ooo re-render table since field lengths may have changed # re-render table since field lengths may have changed
table=$(flatten_table "$table") table=$(flatten_table "$table")
debug "table in csv is: [$table]" debug "table in csv is: [$table]"
@ -1388,6 +1407,7 @@ function runaction() { # runaction <nodes|vms|etc> <actionname> targetlist optio
local actionname line all local actionname line all
local force=0 foreground=0 f rv files n thisfile jqres goterror local force=0 foreground=0 f rv files n thisfile jqres goterror
local good allgoodresults errs allbadresults local good allgoodresults errs allbadresults
# oooo change this
local jqf='[ "_DC_", .job.id, "_OB_", .status ] | @csv' local jqf='[ "_DC_", .job.id, "_OB_", .status ] | @csv'
local jqf_bad='[ "_DC_", "_OB_", .fault.detail, .fault.reason, .status ] | @csv' local jqf_bad='[ "_DC_", "_OB_", .fault.detail, .fault.reason, .status ] | @csv'
local objecttype extrainfo local objecttype extrainfo
@ -1464,6 +1484,8 @@ debug -f "--> extrainfo = $extrainfo"
# Capitalise first letter # Capitalise first letter
objecttype=$(echo ${what:0:1} | tr '[a-z]' '[A-Z]')${what:1} objecttype=$(echo ${what:0:1} | tr '[a-z]' '[A-Z]')${what:1}
# oooo
# change this jq based on thr action
allgoodresults="Server,${objecttype},Job Status" allgoodresults="Server,${objecttype},Job Status"
allbadresults="" allbadresults=""
for f in ${!files[@]} ; do for f in ${!files[@]} ; do
@ -1599,14 +1621,16 @@ function getdata() { # getdata <nodes|vms|etc> <cmd> options
arraycontains opts_a "-n" && usecache=0 || usecache=1 arraycontains opts_a "-n" && usecache=0 || usecache=1
arraycontains opts_a "-e" && errordebug=1 arraycontains opts_a "-e" && errordebug=1
debug "cmd is $cmd"
debug "opts is $opts" debug "opts is $opts"
outfile=$(getarrayopt opts_a o) outfile=$(getarrayopt opts_a o)
refilter=$(getarrayopt opts_a f) refilter=$(getarrayopt opts_a f)
# Allow standard globs rather than regexp globs
[[ $refilter == "*" ]] && refilter=".*" [[ $refilter == "*" ]] && refilter=".*"
if [[ -n $refilter ]]; then if [[ -n $refilter ]]; then
obfilter="select(.name|test(\"^$refilter$\"" obfilter="select(.${ep_defaultfield[$epidx]}|test(\"^$refilter$\""
if [[ $ignorecase -eq 1 ]]; then if [[ $ignorecase -eq 1 ]]; then
obfilter="${obfilter}; \"i\"))" obfilter="${obfilter}; \"i\"))"
else else
@ -1617,8 +1641,8 @@ debug "opts is $opts"
fi fi
[[ -n $refilter ]] && [[ $quiet -eq 0 ]] && info "${what} filter: ^$refilter$" [[ -n $refilter ]] && [[ $quiet -eq 0 ]] && info "${what} filter: ^$refilter$"
# Allow standard globs rather than regexp globs
debug "refilter is $refilter" debug "refilter is $refilter"
debug "obfilter is $obfilter"
# determine jq filter based on object name # determine jq filter based on object name
jqfilter="" jqfilter=""
@ -1645,6 +1669,8 @@ debug "(list) basefilter is $basefilter"
basefilter="${basefilter} + \",\" + (.console|tostring)" basefilter="${basefilter} + \",\" + (.console|tostring)"
fi fi
fi fi
elif [[ $outmode == "raw" ]]; then
[[ $obfilter != "." ]] && basefilter=".[] | $obfilter"
fi fi
elif [[ $cmd == "net" ]]; then elif [[ $cmd == "net" ]]; then
jqscript="$SCRIPTDIR/diagram.jq" jqscript="$SCRIPTDIR/diagram.jq"
@ -1653,6 +1679,8 @@ debug "(list) basefilter is $basefilter"
if [[ $outmode == "verbose" ]]; then if [[ $outmode == "verbose" ]]; then
error "Verbose mode not supported for show command yet" error "Verbose mode not supported for show command yet"
return 1 return 1
elif [[ $outmode == "raw" ]]; then
error "Raw mode not supported for show command yet - try 'list' instead"
else # namesonly else # namesonly
#basefilter=".$jq_obj[] | select(.name|test(\"${arg_array[1]}\"))" #basefilter=".$jq_obj[] | select(.name|test(\"${arg_array[1]}\"))"
basefilter=".[] | $obfilter" basefilter=".[] | $obfilter"
@ -1687,7 +1715,11 @@ debug "awkscript is $awkscript"
done done
wait $pids wait $pids
debug all pids finished debug all pids finished
all=$(cat "$TMPDIR"/get.* 2>/dev/null | tr -d : | egrep -v 'DC|Server' | sed '/^[[:space:]]*$/d') if [[ $outmode == "raw" ]]; then
all=$(cat "$TMPDIR"/get.* 2>/dev/null)
else
all=$(cat "$TMPDIR"/get.* 2>/dev/null | tr -d : | egrep -v 'DC|Server' | sed '/^[[:space:]]*$/d')
fi
if [[ -z $all ]]; then if [[ -z $all ]]; then
fail fail
cat "$TMPDIR"/err.* cat "$TMPDIR"/err.*
@ -1702,7 +1734,7 @@ debug all pids finished
cat "$TMPDIR"/err.* >/dev/stderr cat "$TMPDIR"/err.* >/dev/stderr
fi fi
fi fi
debug "combined results: [$all]" #debug "combined results: [$all]"
end=$(($($GDATE +%s%N)/1000)) end=$(($($GDATE +%s%N)/1000))
lastqsecs=$(echo "scale=2; ($end - $start) / 1000000;" | bc) lastqsecs=$(echo "scale=2; ($end - $start) / 1000000;" | bc)
@ -1956,12 +1988,148 @@ function getnodetypeforadd() {
} }
# populates globals:
# ndcs
# nobs
# dc_ess
# ob_ess
# data
# allobs
# alluids
# o_arr
# ou_arr
function validate_action_obs() { # whattolist actionfilter showerroropt multiple_obs_allowed [retvar_selobname] [retvar_selobuuid]
local whattolist actionfilter showerroropt
local selobname="" selobuuid=""
local retvar_obname retvar_obuuid multiallowed
whattolist="$1"
actionfilter="$2"
showerroropt="$3"
multiallowed="$4"
retvar_obname="$5"
retvar_obuuid="$6"
debug "whattolist=$whattolist"
debug "actionfilter=$actionfilter"
debug "showerroropt=$showerroropt"
debug "multiallowed=$multiallowed"
debug "retvar_obname=$retvar_obname"
debug "retvar_obuuid=$retvar_obuuid"
getdata ${whattolist} list "-f${actionfilter}.*" $showerroropt -c -s -q >"$TMPFILE"
rv=$?
debug "actionfilter=$actionfilter"
if [[ $rv -ne 0 ]]; then
error "Can't find any ${whattolist}s matching '${BOLD}$actionfilter'$PLAIN$RED."
elif [[ ! -e $TMPFILE ]]; then
error "No matching ${whattolist}s found."
elif grep -q "no results" $TMPFILE; then
error "No ${whattolist}s found matching '$obname'."
elif [[ ! -e $TMPFILE ]]; then
error "Results file does not exist."
else
ok
data=$(cat "$TMPFILE" | egrep -v "^$")
ndcs=$( printf %d $(echo "$data" | awk -F, '{ print $1 }' | sort -u | wc -l))
nobs=$( printf %d $(echo "$data" | awk -F, '{ print $2 }' | sort -u | wc -l))
[[ $ndcs -eq 1 ]] && dc_ess="" || dc_ess="s"
[[ $nobs -eq 1 ]] && ob_ess="" || ob_ess="s"
allobs=$(echo "$data" | awk -F, '{ print $2 }' | sort -u)
alluuids=$(echo "$data" | awk -F, '{ print $3 }' | sort -u)
debug "allobs is $allobs"
debug "alluuids is $alluuids"
o_arr=($allobs)
ou_arr=($alluuids)
if [[ $nobs -gt 1 && $multiallowed -eq 0 ]]; then
debug "actionfilter=$actionfilter"
notify_nodots "'${BOLD}${actionfilter}${PLAIN}${PURPLE}' matched multiple ${whattolist}s"
narrowdown "$whattolist" "$allobs" "$alluuids" selobname selobuuid || rv=1
else
selobname="$allobs"
selobuuid="$alluuids"
fi
fi
[[ -n $retvar_obname ]] && eval "$retvar_obname=\"$selobname\""
[[ -n $retvar_obuuid ]] && eval "$retvar_obuuid=\"$selobuuid\""
rm -f "$TMPFILE"
return $rv
}
function narrowdown() { # whattolist "allobs" "all_uuids" retvar_newnodetype retvar_newnodetype_uuid
local whattolist allobs o_arr alluuids ou_arr
local o n rv=0
local newnodetype="" newnodetype_uuid=""
local retvar_newnodetype retvar_newnodetype_uuid
whattolist="$1"
allobs="$2"
alluuids="$3"
retvar_newnodetype="$4"
retvar_newnodetype_uuid="$5"
o_arr=($allobs)
ou_arr=($alluuids)
while [[ -z $newnodetype ]]; do
echo
n=1
while read -r o; do
printf "%3d. %s\n" $n "$o"
n=$((n + 1))
done <<<"$allobs"
echo
getstr ":" "" "Select one (q to abort)"
if [[ -n $retstr ]]; then
if [[ $retstr == "q" ]]; then
rv=1
break
elif [[ $retstr =~ ^[0-9]*$ ]]; then
if [[ $retstr -le 0 || $retstr -ge $n ]]; then
error "Invalid selection"
else
newnodetype="${o_arr[$((retstr - 1))]}"
newnodetype_uuid="${ou_arr[$((retstr - 1))]}"
fi
else
local matched=0 x allmatches="" this thisuuid
for x in ${!o_arr[@]}; do
this="${o_arr[$x]}"
thisuuid="${ou_arr[$x]}"
shopt -s nocasematch
if [[ ${this} =~ $retstr ]]; then
newnodetype="$this"
newnodetype_uuid="$thisuuid"
allmatches="$allmatches [$this]"
matched=$((matched + 1))
fi
shopt -u nocasematch
done
if [[ $matched -eq 0 ]]; then
error "'$retstr' doesn't match any choice"
newnodetype=""
elif [[ $matched -gt 1 ]]; then
error "'$retstr' matched multiple choices: $allmatches"
newnodetype=""
fi
fi
fi
done
eval "$retvar_newnodetype=\"$newnodetype\""
eval "$retvar_newnodetype_uuid=\"$newnodetype_uuid\""
return $rv
}
function processcmd() { function processcmd() {
local cmd arg newarg rv newlocs x err admin idx opts pipe gotargs local cmd arg newarg rv newlocs x err admin idx opts pipe gotargs
local whattolist actionname="" actionfilter="" local whattolist actionname="" actionfilter=""
local showerror=0 showerroropt="" local showerror=0 showerroropt=""
local epidx endpoint origendpoint builtin newname newnodetype newnodetype_uuid local epidx endpoint origendpoint builtin newname
local newnodex=0 newnodey=0 local newnodex=0 newnodey=0
local dev devuuid port portnum adapnum
local BUILTINMODELS="Cloud|VPCS|NAT|Frame Relay switch|Ethernet hub|Ethernet switch" local BUILTINMODELS="Cloud|VPCS|NAT|Frame Relay switch|Ethernet hub|Ethernet switch"
local oldname olduuid local oldname olduuid
cmd=$1 cmd=$1
@ -2063,27 +2231,38 @@ debug "post replacedargs is [$replacedargs]"
error "Name of new $whattolist not provided." error "Name of new $whattolist not provided."
return 1 return 1
fi fi
newnodetype="${arg_array[3]}" # eg. VPCS, Cisco IOS, etc if [[ $endpoint == "node" ]]; then
newnodetype="${arg_array[3]}" # eg. VPCS, Cisco IOS, etc
debug "jjjjj newname is $newname" # is it a builtin appliance?
debug "jjjjj newnodetype is $newnodetype" if [[ $newnodetype =~ ^($BUILTINMODELS)$ ]]; then
debug "jjjjj whattolist is $whattolist" debug "adding a gns3 built-in node ($newnodetype)"
builtin=1
# is it a builtin appliance? whattolist="model"
if [[ $newnodetype =~ ^($BUILTINMODELS)$ ]]; then actionfilter="-f.*${newnodetype}.*"
debug "adding a gns3 built-in node ($newnodetype)" else
builtin=1 debug "adding a gns3 appliance ($newnodetype)"
#whattolist="" builtin=0
#newnodetype=$(getnodetypeforadd $newnodetype) # we will lookup the template ID of "nodetype" later...
#newnodetype_uuid="" whattolist="model"
whattolist="model" actionfilter="-f.*${newnodetype}.*"
actionfilter="-f.*${newnodetype}.*" fi
else elif [[ $endpoint == "link" ]]; then
debug "adding a gns3 appliance ($newnodetype)" local x idx failed=0
builtin=0 idx=2
# we will lookup the template ID of "nodetype" later... for x in 0 1; do
whattolist="model" dev[$x]=${arg_array[$idx]}; idx=$((idx + 1))
actionfilter="-f.*${newnodetype}.*" port[$x]=${arg_array[$idx]}; idx=$((idx + 1))
# replace * with .*
port[$x]=$(echo "${port[$x]}" | sed 's#[^\.]\*#\.\*#g')
if [[ -z ${dev[$x]} || -z ${port[$x]} ]]; then
failed=1
fi
done
if [[ $failed -eq 1 ]]; then
error "usage: action link add adev aport zdev zport"
return 1
fi
fi fi
elif [[ $actionname == "mv" ]]; then elif [[ $actionname == "mv" ]]; then
oldname=${arg_array[2]} oldname=${arg_array[2]}
@ -2179,126 +2358,89 @@ debug "jjjjj whattolist is $whattolist"
fi fi
if [[ -n $whattolist ]]; then if [[ -n $whattolist ]]; then
local ndcs nobs data confirm=0
# Get a list of objects to operate on # Get a list of objects to operate on
# ie. turn regexp into a list of dcs and obnames first # ie. turn regexp into a list of dcs and obnames first
getdata ${whattolist} list $actionfilter $showerroropt -c -s -q >"$TMPFILE" echo
rv=$? if [[ $actionname == "connect" || $actionname == "mv" ]]; then
if [[ $rv -ne 0 ]]; then validate_action_obs ${whattolist} "$actionfilter" "$showerroropt" $NOMULTI || return $?
error "Query for matching ${whattolist}s failed." if [[ $nobs -gt 1 ]]; then
rv=1 local allobs=$(echo "$data" | awk -F, '{ print $2 }' | sort -u | tr '\n' ',')
elif [[ ! -e $TMPFILE ]]; then error "Can't run '$actionname' with multiple objects (matched: ${allobs%,})"
error "No matching ${whattolist}s found." return 1
rv=1 else
elif grep -q "no results" $TMPFILE; then confirm=1
error "No ${whattolist}s found matching '$obname'." fi
rv=1 elif [[ $actionname == "add" ]]; then
elif [[ ! -e $TMPFILE ]]; then if [[ $endpoint == "node" ]]; then
error "Results file does not exist." validate_action_obs ${whattolist} "$actionfilter" "$showerroropt" $NOMULTI newnodetype newnodetype_uuid
rv=1
else
local ndcs nobs data confirm=0
ok
debug "tmpfile contents: [$(cat $TMPFILE)]"
echo
data=$(cat "$TMPFILE" | egrep -v "^$")
# how many servers?
ndcs=$( printf %d $(echo "$data" | awk -F, '{ print $1 }' | sort -u | wc -l))
[[ $ndcs -eq 1 ]] && dc_ess="" || dc_ess="s"
nobs=$( printf %d $(echo "$data" | awk -F, '{ print $2 }' | sort -u | wc -l))
[[ $nobs -eq 1 ]] && ob_ess="" || ob_ess="s"
if [[ $actionname == "connect" || $actionname == "mv" ]]; then
if [[ $nobs -gt 1 ]]; then
local allobs=$(echo "$data" | awk -F, '{ print $2 }' | sort -u | tr '\n' ',')
error "Can't run '$actionname' with multiple objects (matched: ${allobs%,})"
return 1
else
confirm=1
fi
elif [[ $actionname == "add" ]]; then
local allobs alluuids o_arr ou_arr
allobs=$(echo "$data" | awk -F, '{ print $2 }' | sort -u)
alluuids=$(echo "$data" | awk -F, '{ print $3 }' | sort -u)
o_arr=($allobs)
ou_arr=($alluuids)
if [[ $nobs -gt 1 ]]; then
local o n
info "Matched multiple ${whattolist}s:"
newnodetype=""
while [[ -z $newnodetype ]]; do
echo
n=1
while read -r o; do
printf "%3d. %s\n" $n "${o_arr[$n]}"
n=$((n + 1))
done <<<"$allobs"
echo
getstr ":" "" "Select one (q to abort)"
if [[ -n $retstr ]]; then
if [[ $retstr == "q" ]]; then
break
elif [[ $retstr =~ ^[0-9]*$ ]]; then
if [[ $retstr -le 0 || $retstr -ge $n ]]; then
error "Invalid selection"
else
newnodetype="${o_arr[$retstr]}"
newnodetype_uuid="${ou_arr[$retstr]}"
fi
else
local matched=0 x allmatches="" this thisuuid
for x in ${!o_arr[@]}; do
this="${o_arr[$x]}"
thisuuid="${ou_arr[$x]}"
shopt -s nocasematch
if [[ ${this} =~ $retstr ]]; then
newnodetype="$this"
newnodetype_uuid="$thisuuid"
allmatches="$allmatches [$this]"
matched=$((matched + 1))
fi
shopt -u nocasematch
done
if [[ $matched -eq 0 ]]; then
error "'$retstr' doesn't match any choice"
newnodetype=""
elif [[ $matched -gt 1 ]]; then
error "'$retstr' matched multiple choices: $allmatches"
newnodetype=""
fi
fi
fi
done
else
newnodetype="$allobs"
newnodetype_uuid="$alluuids"
fi
if [[ -z $newnodetype ]]; then if [[ -z $newnodetype ]]; then
confirm=0 confirm=0
else else
debug "newnodetype is $newnodetype"
debug "newnodeuuid is $newnodetype_uuid"
notify_nodots "Adding a new ${BOLD}$newnodetype${PLAIN}${PURPLE} named $BOLD$newname${PLAIN}" notify_nodots "Adding a new ${BOLD}$newnodetype${PLAIN}${PURPLE} named $BOLD$newname${PLAIN}"
confirm=1 confirm=1
fi fi
else # action is not add/connect elif [[ $endpoint == "link" ]]; then
echo -e "${PURPLE}About to run '${BOLD}$actionname${PLAIN}${PURPLE}' on ${BOLD}${nobs}${PLAIN}${PURPLE} ${whattolist}${ob_ess} on ${BOLD}${ndcs}${PLAIN}${PURPLE} server${dc_ess}:${PLAIN}" local x json adaplist portnumlist portlist nports newn newu jqs
echo "$data" | awk -F, "BEGIN {lastdc=\"\"} { if (\$1 != lastdc) { print \" ${YELLOW}- ${BOLD}\" \$1 \"${PLAIN}\"; lastdc=\$1; } print \" ${YELLOW}- \" \$2 \"${PLAIN}\"}" local jqs_name jqs_num
for x in 0 1; do
echo local letter portlower
if [[ $ndcs -le 1 ]]; then [[ $x -eq 0 ]] && letter=A || letter=Z
getyn n "Really proceed" debug "about to validate link $x"
[[ $? -eq 0 ]] && confirm=1 || confirm=0 validate_action_obs "node" "${dev[$x]}" "$showerroropt" $NOMULTI newn newu || return $?
else dev[$x]="$newn"
local confirmcode entered_string devuuid[$x]="$newu"
confirmcode=$(generate_random_string) debug "${letter}-node ${dev[$x]} is OK (${dev[$x]})"
notify_nodots "Confirmation code is: ${BOLD}${confirmcode}${PLAIN}" debug "getting node $x ports"
getstr ":" "n" "Enter the above code to proceed, anything else will abort" json=$(getdata nodes list -q -e -r "-f${dev[$x]}")
entered_string="$retstr" portlower=$(echo ${port[$x]} | tr 'A-Z' 'a-z')
[[ $entered_string == $confirmcode ]] && confirm=1 || confirm=0 jqs=".ports[] | select(.name|ascii_downcase|test(\".*${portlower}.*\"))"
fi jqs_name="${jqs} | .short_name"
jqs_num="${jqs} | .port_number"
jqs_adapnum="${jqs} | .adapter_number"
portlist=$(echo "$json" | jq -r "$jqs_name")
portnumlist=$(echo "$json" | jq -r "$jqs_num")
adapnumlist=$(echo "$json" | jq -r "$jqs_adapnum")
debug "portlist is $portlist"
debug "portnumlist is $portnumlist"
debug "adapnumlist is $adapnumlist"
#debug "raw port data is\n$json"
nports=$(wc -l <<< "$portlist" | bc)
if [[ -z $portlist || $nports -eq 0 ]]; then
error "${letter}-node ${BOLD}${dev[$x]}$PLAIN$RED has no ports matching '${BOLD}${port[$x]}$PLAIN$RED'."
elif [[ $nports -gt 1 ]]; then
error "${letter}-node ${BOLD}${dev[$x]}$PLAIN$RED has multiple ports matching '${BOLD}${port[$x]}$PLAIN$RED':"
echo -e "${RED}$portlist${PLAIN}" | sed -e 's/^/ /'
else
port[$x]="$portlist"
portnum[$x]="$portnumlist"
adapnum[$x]="$adapnumlist"
debug "${letter}-node ${dev[$x]} port ${port[$x]} is OK (${dev[$x]})"
fi
done
notify_nodots "Adding a link from ${BOLD}${dev[0]} ${port[0]}${PLAIN}${PURPLE} to ${BOLD}${dev[1]} ${port[1]}${PLAIN}"
confirm=1
fi fi
fi # end if data query got results else # action is not add/connect
validate_action_obs ${whattolist} "$actionfilter" "$showerroropt" $MULTI || return $?
echo -e "${PURPLE}About to run '${BOLD}$actionname${PLAIN}${PURPLE}' on ${BOLD}${nobs}${PLAIN}${PURPLE} ${whattolist}${ob_ess} on ${BOLD}${ndcs}${PLAIN}${PURPLE} server${dc_ess}:${PLAIN}"
echo "$data" | awk -F, "BEGIN {lastdc=\"\"} { if (\$1 != lastdc) { print \" ${YELLOW}- ${BOLD}\" \$1 \"${PLAIN}\"; lastdc=\$1; } print \" ${YELLOW}- \" \$2 \"${PLAIN}\"}"
echo
if [[ $ndcs -le 1 ]]; then
getyn n "Really proceed"
[[ $? -eq 0 ]] && confirm=1 || confirm=0
else
local confirmcode entered_string
confirmcode=$(generate_random_string)
notify_nodots "Confirmation code is: ${BOLD}${confirmcode}${PLAIN}"
getstr ":" "n" "Enter the above code to proceed, anything else will abort"
entered_string="$retstr"
[[ $entered_string == $confirmcode ]] && confirm=1 || confirm=0
fi
fi
else else
# we dont need to do a data query # we dont need to do a data query
newnodetype_uuid="" newnodetype_uuid=""
@ -2308,30 +2450,45 @@ debug "jjjjj whattolist is $whattolist"
if [[ $confirm -eq 1 ]]; then if [[ $confirm -eq 1 ]]; then
if [[ $actionname == "add" ]]; then if [[ $actionname == "add" ]]; then
local postdata local postdata
# We use alternate values for the actiontarget string here: if [[ $endpoint == "node" ]]; then
# loc=servername (normal) # We use alternate values for the actiontarget string here:
# ob=name of new ob to add # loc=servername (normal)
# obuuid=uuid of model # ob=name of new ob to add
# extrainfo=curl post data in the form of key1:val1^key2:val2... # obuuid=uuid of model
# extrainfo=curl post data in the form of key1:val1^key2:val2...
# the endpoint we call depends on whether # the endpoint we call depends on whether
# we are adding a gns3 builtin node or an appliance # we are adding a gns3 builtin node or an appliance
if [[ $builtin -eq 1 ]]; then if [[ $builtin -eq 1 ]]; then
local nodetypeforadd local nodetypeforadd
# gns3 wants the nodetype in the post data and in a # gns3 wants the nodetype in the post data and in a
# special format. # special format.
nodetypeforadd=$(getnodetypeforadd $newnodetype) nodetypeforadd=$(getnodetypeforadd $newnodetype)
postdata="name:$newname^node_type:$nodetypeforadd^compute_id:local^template_id:$newnodetype_uuid" postdata="name:$newname^node_type:$nodetypeforadd^compute_id:local^template_id:$newnodetype_uuid"
# ...and NOT in the URL # ...and NOT in the URL
newnodetype="" newnodetype=""
newnodetype_uuid="" newnodetype_uuid=""
else else
# ie. use an appliance template # ie. use an appliance template
postdata="x:$newnodex^y:$newnodey" postdata="x:$newnodex^y:$newnodey"
endpoint="model" endpoint="model"
fi
actiontargets="$curlocs,$newname,$newnodetype_uuid,$postdata"
#actiontargets="${actiontargets},$postdata"
elif [[ $endpoint == "link" ]]; then
#POST 'http://localhost:3080/v2/projects/bfb83f16-dab4-445a-a572-d7cc1801222e/links' -d '{"nodes": [{"adapter_number": 0, "label": {"text": "Text", "x": 42, "y": 0}, "node_id": "d3601934-e39a-4865-9cf5-3e46e1fe24e2", "port_number": 3}, {"adapter_number": 0, "node_id": "d3601934-e39a-4865-9cf5-3e46e1fe24e2", "port_number": 4}]}'
RAWJSONPOSTDATA="{\"nodes\": ["
for n in 0 1; do
RAWJSONPOSTDATA="${RAWJSONPOSTDATA}{\"node_id\": \"${devuuid[$n]}\", \"adapter_number\": ${adapnum[$n]}, \"port_number\": ${portnum[$n]}}"
[[ $n -eq 0 ]] && RAWJSONPOSTDATA="${RAWJSONPOSTDATA},"
done
RAWJSONPOSTDATA="${RAWJSONPOSTDATA}]}"
echo -e "${YELLOW}${BOLD}rawjson is:\n${RAWJSONPOSTDATA}${PLAIN}" >/dev/stderr
actiontargets="$curlocs,,,"
fi fi
actiontargets="$curlocs,$newname,$newnodetype_uuid"
actiontargets="${actiontargets},$postdata"
elif [[ $actionname == "mv" ]]; then elif [[ $actionname == "mv" ]]; then
oldname=$(echo "$data" | awk -F, '{ print $2 }' | sort -u) oldname=$(echo "$data" | awk -F, '{ print $2 }' | sort -u)
olduuid=$(echo "$data" | awk -F, '{ print $3 }' | sort -u) olduuid=$(echo "$data" | awk -F, '{ print $3 }' | sort -u)
@ -2361,14 +2518,13 @@ debug " opts = ${opts[@]}"
debug " outputfile = ${TMPFILE}" debug " outputfile = ${TMPFILE}"
runaction ${endpoint} $actionname "$actiontargets" ${opts[@]} >"$TMPFILE" runaction ${endpoint} $actionname "$actiontargets" ${opts[@]} >"$TMPFILE"
rv=$? rv=$?
if [[ $actionname == "add" && $rv -eq 0 && $builtin -eq 0 ]]; then if [[ $actionname == "add" && $origendpoint == "node" && $rv -eq 0 && $builtin -eq 0 ]]; then
local fail=0 local fail=0
# we now need to rename the newly created object - gns3 # we now need to rename the newly created object - gns3
# will always generate a name based on the template # will always generate a name based on the template
debug "json is $JSON_RESULTS" debug "json is $JSON_RESULTS"
json_extract "$JSON_RESULTS" .name oldname .node_id olduuid json_extract "$JSON_RESULTS" .name oldname .node_id olduuid
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
info "Now need to rename '$oldname' to '$newname'..."
runaction ${origendpoint} mv "$curlocs,$oldname,$olduuid,name:$newname^" -F runaction ${origendpoint} mv "$curlocs,$oldname,$olduuid,name:$newname^" -F
[[ $? -ne 0 ]] && fail=1 [[ $? -ne 0 ]] && fail=1
else else
@ -2598,6 +2754,13 @@ LINK="$BLUE$UNDERLINE"
UNDERLINE_PRINTED=$(echo -en "$UNDERLINE") UNDERLINE_PRINTED=$(echo -en "$UNDERLINE")
UNDERLINE_LENGTH=${#UNDERLINE_PRINTED} UNDERLINE_LENGTH=${#UNDERLINE_PRINTED}
NOMULTI=0
MULTI=1
NOQUOTES=0
QUOTES=1
REALLYNOQUOTES=-1
CURLERRORSTRINGS="(^40.:|error|status.*40.)" CURLERRORSTRINGS="(^40.:|error|status.*40.)"
# Generate sed script to add colours to certain words # Generate sed script to add colours to certain words
@ -2635,8 +2798,9 @@ addendpoint nodes projects/_CURPROJECT_/nodes node node_id name
addendpoint links projects/_CURPROJECT_/links link link_id link_id addendpoint links projects/_CURPROJECT_/links link link_id link_id
addepalias links l addepalias links l
addeptitles links "Type" "A-Host_UUID " "A-Port" "Z-Host_UUID " "Z-Port" addeptitles links "Type" "A-Host_UUID " "A-Port" "Z-Host_UUID " "Z-Port" "ID _"
addepfields links ".link_type" ".nodes[0].node_id" ".nodes[0].label.text" ".nodes[1].node_id" ".nodes[1].label.text" addepfields links ".link_type" ".nodes[0].node_id" ".nodes[0].label.text" ".nodes[1].node_id" ".nodes[1].label.text" ".link_id"
addepactions links add del
addendpoint models templates model template_id name addendpoint models templates model template_id name
addepalias models m addepalias models m
@ -2663,7 +2827,7 @@ addcmd show "Show detail of a given element (eg. compute node, VM, etc)" 2 sh
addcmd net "Show network diagram (requires perl Graph::Easy)" addcmd net "Show network diagram (requires perl Graph::Easy)"
addcmd action "Perform action on given object." 3 act do addcmd action "Perform action on given object" 3 act do
declare -a lines declare -a lines
for x in ${!ep_jqobj[@]}; do for x in ${!ep_jqobj[@]}; do
if [[ -z ${ep_validactions[$x]} ]]; then if [[ -z ${ep_validactions[$x]} ]]; then
@ -2672,7 +2836,7 @@ addcmd action "Perform action on given object." 3 act do
lines+=("${ep_jqobj[$x]} actions: ${ep_validactions[$x]}") lines+=("${ep_jqobj[$x]} actions: ${ep_validactions[$x]}")
fi fi
done done
addcmdusage action "object_type action_type regexp_filter" "object_type can be: [${ep_jqobj[*]}]" "" "${lines[@]}" addcmdusage action "object_type action_type regexp_filter [extrainfo]" "object_type can be: [${ep_jqobj[*]}]" "" "${lines[@]}"
addcmdoption action "-f" "Force - don't ask for confirmation" addcmdoption action "-f" "Force - don't ask for confirmation"
addcmdalias "open" "action project open" "_CURPROJECT_" addcmdalias "open" "action project open" "_CURPROJECT_"
@ -2685,6 +2849,9 @@ addcmdalias "add" "action node add" ""
addcmdalias "rm" "action node del" "" addcmdalias "rm" "action node del" ""
addcmdalias "del" "action node del" "" addcmdalias "del" "action node del" ""
addcmdalias "mv" "action node mv" "" addcmdalias "mv" "action node mv" ""
addcmdalias "link" "action link add" ""
addcmdalias "unlink" "action link del" ""
addcmdalias "delink" "action link del" ""
addcmd help "List regular commands" 0 "?" "h" addcmd help "List regular commands" 0 "?" "h"
addcmd exit "Exit from gnscli" 0 quit addcmd exit "Exit from gnscli" 0 quit
@ -2776,12 +2943,13 @@ notify "Getting initial projectlist"
oldverbose=$VERBOSE oldverbose=$VERBOSE
VERBOSE=1 VERBOSE=1
errfile="$TMPDIR"/err errfile="$TMPDIR"/err
output=$(getdata projects show -e -r 2>"$errfile") output=$(getdata projects list -e -r 2>"$errfile")
rv=$? rv=$?
debug "rv is $rv"
VERBOSE=$oldverbose VERBOSE=$oldverbose
if [[ $rv -eq 0 ]]; then if [[ $rv -eq 0 ]]; then
ok ok
#cat "$errfile" cat "$errfile"
rm -f "$errfile" rm -f "$errfile"
jqoutput=$(echo "$output" | jq -r '.[] | .project_id + "|" + .name' 2>"$errfile") jqoutput=$(echo "$output" | jq -r '.[] | .project_id + "|" + .name' 2>"$errfile")
rv=$? rv=$?
@ -2915,10 +3083,10 @@ END {
"UUID#" + .link_id, "UUID#" + .link_id,
"Type#" + .link_type, "Type#" + .link_type,
"Project UUID#" + .project_uuid, "Project UUID#" + .project_uuid,
"A-Node#" + .node[0].node_id, "A-Node#" + .nodes[0].node_id,
"A-Port#" + .node[0].label.text, "A-Port#" + .nodes[0].label.text,
"Z-Node#" + .node[1].node_id, "Z-Node#" + .nodes[1].node_id,
"Z-Port#" + .node[1].label.text, "Z-Port#" + .nodes[1].label.text,
"Capturing#" + (.capturing|tostring), "Capturing#" + (.capturing|tostring),
"Suspended#" + (.suspend|tostring), "Suspended#" + (.suspend|tostring),
"__END__" "__END__"