Work.on adding 'add' command

added connect command
This commit is contained in:
Rob Pearce 2021-12-23 16:14:39 +11:00
parent 66ae26f8da
commit 6c268c3f3b
1 changed files with 240 additions and 55 deletions

295
gnscli.sh
View File

@ -1,5 +1,10 @@
#!/bin/bash
# add node
# issue with json post data
# rename project
# delete node
# node stop givesjq error
# connect xxx & [opens iterm (or whatever)]
@ -300,8 +305,18 @@ function profile() {
}
function debug() {
local force=0
if [[ $1 == "-f" ]]; then
shift
force=1
fi
if [[ $VERBOSE -eq 1 ]]; then
echo -e "${PURPLE}${BOLD}${FUNCNAME[1]}(): ${PLAIN}${PURPLE}$*${PLAIN}" 1>&2
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}" >/tmp/a
else
echo -e "${PURPLE}${BOLD}${FUNCNAME[1]}(): ${PLAIN}${PURPLE}$*${PLAIN}" 1>&2
fi
fi
}
@ -755,21 +770,51 @@ function runcurlget() { # location api_endpoint(ovname)
return $rv
}
function runcurlaction() { # location api_endpoint(ovname) obname ovmethod
function runcurldatapost() { # location api_endpoint "curl data"
local thisapi thisurl curlres rv
#local thisauthdom u p thisauthstr
local loc api_endpoint obname ovmethod
#local data="<action/>"
local data=""
loc="$1"
api_endpoint="$2"
obname="$3"
ovmethod="$4"
data="$3"
thisapi=$(get $loc api)
[[ -z $thisapi ]] && echo "cant find api for '$loc'" && return 1
#thisauthdom=$(get $loc authdomain)
thisurl="$thisapi/$api_endpoint/$obname/$ovmethod"
debug -f "data is $data"
thisurl="$thisapi/$api_endpoint"
thisurl=${thisurl/_CURPROJECT_/$curprojid}
debug -f "curl -XPOST -sk --header 'Content-type: application/xml' --header 'Accept: application/json' -d \"$data\" $thisurl"
set -x
curlres=$(curl -XPOST -sk --header 'Content-type: application/xml' --header 'Accept: application/json' -d "$data" $thisurl)
set +x
rv=$?
[[ $rv -ne 0 ]] && error "curl POST to $thisurl failed"
echo "$curlres"
return $rv
}
function runcurlaction() { # location api_endpoint(ovname) obname ovmethod ["curl data"]
local thisapi thisurl curlres rv
#local thisauthdom u p thisauthstr
local loc api_endpoint obname ovmethod
local data=""
#local data="<action/>"
loc="$1"
api_endpoint="$2"
obname="$3"
ovmethod="$4"
data="$5"
thisapi=$(get $loc api)
[[ -z $thisapi ]] && echo "cant find api for '$loc'" && return 1
#thisauthdom=$(get $loc authdomain)
debug -f "data is $data"
thisurl="$thisapi/$api_endpoint/$obname"
[[ -n $ovmethod ]] && thisurl="${thisurl}/$ovmethod"
thisurl=${thisurl/_CURPROJECT_/$curprojid}
#u=$(head -1 "$AUTHFILE")
#p=$(tail -1 "$AUTHFILE")
@ -777,7 +822,7 @@ function runcurlaction() { # location api_endpoint(ovname) obname ovmethod
#unset u
#unset p
[[ $VERBOSE -eq 1 ]] && debug "curl -XPOST -sk --header 'Content-type: application/xml' --header 'Accept: application/json' -d \"$data\" $thisurl"
debug -f "curl -XPOST -sk --header 'Content-type: application/xml' --header 'Accept: application/json' -d \"$data\" $thisurl"
curlres=$(curl -XPOST -sk --header 'Content-type: application/xml' --header 'Accept: application/json' -d "$data" $thisurl)
rv=$?
@ -830,6 +875,7 @@ function getgnsmethod() {
close) echo "close";;
start) echo "start";;
stop) echo "stop";;
add) echo "";;
#migrate) echo "migrate";;
*)
echo
@ -839,10 +885,26 @@ function getgnsmethod() {
return $rv
}
function runaction_loc() { # runaction_loc syd|etc api_endpoint action_name ob_uuid ob_name [options]
function makejson() { # makejson key1:val1^key2:val2^...
local plaindata tok toks key val tnum=1
plaindata="$1"
printf "%s" '{'
IFS='^' read -ra toks <<< "$plaindata"
for tok in "${toks[@]}"; do
[[ $tnum -ne 1 ]] && printf "%s" ","
key=${tok%:*}
val=${tok#*:}
printf '"%s":"%s"' "$key" "$val"
tnum=$((tnum + 1))
done
printf "%s\n" '}'
}
function runaction_loc() { # runaction_loc syd|etc api_endpoint action_name ob_uuid ob_name "extra info" [options]
local thisgrid thisauthdom thisurl thisauthstr curlres loc u p
local api_endpoint jq_obj opts opts_arr deffield epidx r1 r2 rv
local actionname method trv extrainfo
local curldata="" crv
rv=0
loc="$1"
@ -861,6 +923,12 @@ function runaction_loc() { # runaction_loc syd|etc api_endpoint action_name ob_u
opts="$*"
opts_arr=( $opts )
debug -f "extrainfo : $extrainfo"
debug -f "remaining opts: $opts"
if [[ $actionname == "add" ]]; then
curldata=$(makejson "$extrainfo")
fi
# special case
if [[ $actionname == "connect" ]]; then
local locidx
@ -895,18 +963,25 @@ function runaction_loc() { # runaction_loc syd|etc api_endpoint action_name ob_u
return 1
fi
debug "location: ${loc}"
debug "api endpoint: ${api_endpoint}"
debug "jq obj: ${jq_obj}"
debug "actionname: ${actionname} (gns method: $method)"
debug "obname: ${ob}"
debug "options: ${opts}"
debug -f "location: ${loc}"
debug -f "api endpoint: ${api_endpoint}"
debug -f "jq obj: ${jq_obj}"
debug -f "actionname: ${actionname} (gns method: '$method')"
debug -f "obname: ${ob}"
debug -f "options: ${opts}"
debug -f "curldata: ${curldata}"
curlres=$(runcurlaction $loc $api_endpoint $ob $method )
if [[ $? -ne 0 ]]; then
if [[ $action == "add" ]]; then
curlres=$(runcurldatapost $loc $api_endpoint "$curldata" )
crv=$?
else
curlres=$(runcurlaction $loc $api_endpoint $ob $method "$curldata" )
crv=$?
fi
if [[ $crv -ne 0 ]]; then
rv=1
fi
debug "curlres is [$curlres]"
debug -f "curlres is [$curlres]"
echo "$curlres"
fi
return $rv
@ -1193,7 +1268,6 @@ function runaction() { # runaction <nodes|vms|etc> <actionname> targetlist optio
epidx=$(getepidx $what)
[[ $? -ne 0 ]] && error "unknown endpoint '$what'" && return 1
jq_obj="${ep_jqobj[$epidx]}"
api_endpoint="${ep_apiendpoint[$epidx]}"
[[ -z $api_endpoint ]] && error "no endpointname for endpoint '$what'" && return 1
@ -1211,16 +1285,17 @@ debug "opts is $opts"
loc=$(echo "$line" | cut -d, -f1)
ob=$(echo "$line" | cut -d, -f2)
obuuid=$(echo "$line" | cut -d, -f3)
extrainfo=$(echo "$line" | cut -d, -f4)
runaction_loc $loc $epidx $actionname $obuuid $ob $extrainfo $opts > "$TMPDIR/run,$loc,$ob"
extrainfo="$(echo "$line" | cut -d, -f4-)"
runaction_loc $loc $epidx $actionname $obuuid $ob "$extrainfo" $opts > "$TMPDIR/run,$loc,$ob"
else
pids=""
while read -r line ; do
loc=$(echo "$line" | cut -d, -f1)
ob=$(echo "$line" | cut -d, -f2)
obuuid=$(echo "$line" | cut -d, -f3)
extrainfo=$(echo "$line" | cut -d, -f4)
runaction_loc $loc $epidx $actionname $obuuid $ob $extrainfo $opts > "$TMPDIR/run,$loc,$ob" &
extrainfo=$(echo "$line" | cut -d, -f4-)
debug "extrainfo is: $extrainfo"
runaction_loc $loc $epidx $actionname $obuuid $ob "$extrainfo" $opts > "$TMPDIR/run,$loc,$ob" &
pids="$pids $!"
done <<< "$targetlist"
@ -1236,7 +1311,7 @@ debug "opts is $opts"
# Capitalise first letter
objecttype=$(echo ${what:0:1} | tr '[a-z]' '[A-Z]')${what:1}
allgoodresults="Server,${objecttype},Job Status"
allbadresults="Server,${objecttype},Detail,Reason,Status"
allbadresults=""
for f in ${!files[@]} ; do
local thiscsv
thisfile="${files[$f]}"
@ -1255,12 +1330,15 @@ debug "opts is $opts"
goterror=1
elif [[ ${ACTIONRES_MSG[$n]} == *rror* ]]; then
goterror=1
elif [[ ${ACTIONRES_MSG[$n]} == *message* ]]; then
goterror=1
else
goterror=0
fi
if [[ $goterror -eq 1 ]]; then
thiscsv_bad=$(echo "${ACTIONRES_MSG[$n]}" | jq -r "${jqf_bad}" | sed -e "s/_DC_/${ACTIONRES_LOC[$n]}/g" | sed -e "s/_OB_/${ACTIONRES_OB[$n]}/" | tr -d '"[]' | egrep -v "^$")
#thiscsv_bad=$(echo "${ACTIONRES_MSG[$n]}" | jq -r "${jqf_bad}" | sed -e "s/_DC_/${ACTIONRES_LOC[$n]}/g" | sed -e "s/_OB_/${ACTIONRES_OB[$n]}/" | tr -d '"[]' | egrep -v "^$")
thiscsv_bad=$(echo "${ACTIONRES_MSG[$n]}" | jq -r . | sed -e "s/_DC_/${ACTIONRES_LOC[$n]}/g" | sed -e "s/_OB_/${ACTIONRES_OB[$n]}/" | egrep -v "^$")
allbadresults="${allbadresults}\n${thiscsv_bad}"
errs=$((errs + 1))
@ -1277,9 +1355,10 @@ debug "opts is $opts"
echo
if [[ $errs -gt 0 ]]; then
local fullres_bad
echo -e "${RED}$errs x '${BOLD}$actionname${PLAIN}${RED}' actions failed.${PLAIN}"
fullres_bad=$(csv_to_table $(($errs + 1)) "$allbadresults")
echo "$fullres_bad"
echo -e "${RED}$errs x '${BOLD}$actionname${PLAIN}${RED}' actions failed:${PLAIN}"
echo -e "${RED}"
echo "$allbadresults" | sed -e 's/^/ /'
echo -e "${PLAIN}"
echo
fi
@ -1327,7 +1406,7 @@ function getdata() { # getdata <nodes|vms|etc> <cmd> options
local usecache refilter
local w greenwords yellowwords redwords uuidcol
local errordebug=0
local quiet=0
local quiet=0 ignorecase=0
start=$(($(gdate +%s%N)/1000))
lastqsecs=""
@ -1358,6 +1437,7 @@ function getdata() { # getdata <nodes|vms|etc> <cmd> options
arraycontains opts_a "-q" && quiet=1
arraycontains opts_a "-v" && outmode=verbose
arraycontains opts_a "-s" && outmode=namesonly
arraycontains opts_a "-c" && ignorecase=1
arraycontains opts_a "-n" && usecache=0 || usecache=1
arraycontains opts_a "-e" && errordebug=1
@ -1368,7 +1448,16 @@ debug "opts is $opts"
refilter=$(getarrayopt opts_a f)
[[ $refilter == "*" ]] && refilter=".*"
[[ -n $refilter ]] && obfilter="select(.name|test(\"^$refilter$\"))" || obfilter="."
if [[ -n $refilter ]]; then
obfilter="select(.name|test(\"^$refilter$\""
if [[ $ignorecase -eq 1 ]]; then
obfilter="${obfilter}; \"i\"))"
else
obfilter="${obfilter}))"
fi
else
obfilter="."
fi
[[ -n $refilter ]] && [[ $quiet -eq 0 ]] && info "${what} filter: ^$refilter$"
# Allow standard globs rather than regexp globs
@ -1667,7 +1756,7 @@ function processcmd() {
local cmd arg newarg rv newlocs x err admin idx opts pipe gotargs
local whattolist actionname="" actionfilter=""
local showerror=0 showerroropt=""
local epidx
local epidx endpoint newname newtype newtype_uuid
cmd=$1
shift
arg="$*"
@ -1746,20 +1835,43 @@ debug "post replacedargs is [$replacedargs]"
fi
obname="" # global
if [[ $cmd == "show" ]]; then
whattolist=${arg_array[0]} && unset 'arg_array[0]'
endpoint=${arg_array[0]} && unset 'arg_array[0]'
whattolist=${endpoint}
[[ ${#arg_array[@]} -ge 1 ]] && opts+=("-f${arg_array[@]}")
elif [[ $cmd == "list" ]]; then
whattolist=${arg_array[0]} && unset 'arg_array[0]'
endpoint=${arg_array[0]} && unset 'arg_array[0]'
whattolist=${endpoint}
[[ ${#arg_array[@]} -ge 1 ]] && opts+=("-f${arg_array[@]}")
elif [[ $cmd == "action" ]]; then
whattolist=${arg_array[0]} && unset 'arg_array[0]'
endpoint=${arg_array[0]} && unset 'arg_array[0]'
whattolist=${endpoint}
actionname=${arg_array[1]} && unset 'arg_array[1]'
if [[ ${#arg_array[@]} -ge 1 ]]; then
actionfilter="-f${arg_array[@]}"
obname="${arg_array[@]}"
if [[ $actionname == "add" ]]; then
newname=${arg_array[2]}
if [[ -z $newname ]]; then
error "Name of new $whattolist not provided."
return 1
fi
# ie. look for models named 'IOS'
# oooo ...if we find one, check its template_type
# if it's qemu then use template_id to figure out appliance id???
# otherwise just use template_type
whattolist="model"
newtype=".*${arg_array[3]}.*"
actionfilter="-f${newtype}"
else
error "Name of $whattolist not provided."
return 1
# start/stop/etc
if [[ ${#arg_array[@]} -ge 1 ]]; then
actionfilter="-f${arg_array[@]}"
obname="${arg_array[@]}"
else
error "Name of $whattolist not provided."
return 1
fi
fi
fi
@ -1826,32 +1938,27 @@ debug "post replacedargs is [$replacedargs]"
action)
# TODO: ooremove any output format opts
validate_action ${whattolist} $actionname
validate_action ${endpoint} $actionname
if [[ $? -ne 0 ]]; then
error "'$actionname' is not a valid action for ${whattolist}s"
error "'$actionname' is not a valid action for ${endpoint}s"
return 1
fi
epidx=$(getepidx $whattolist)
epidx=$(getepidx $endpoint)
if [[ $? -ne 0 ]]; then
error "'$whattolist' is not a valid endpoint"
error "'$endpoint' is not a valid endpoint"
return 1
fi
# When getting a list of what to operate on, we need
# to get the ID as well as the name, and the ID field
# depends on the obejct type.
#action_idfield=${ep_idfield[$epidx]}
# Get a list of objects to operate on
# ie. turn regexp into a list of dcs and obnames first
getdata ${whattolist} list $actionfilter $showerroropt -s -q >"$TMPFILE"
getdata ${whattolist} list $actionfilter $showerroropt -c -s -q >"$TMPFILE"
rv=$?
if [[ $rv -ne 0 ]]; then
error "Query for matching objects failed."
error "Query for matching ${whattolist}s failed."
rv=1
elif [[ ! -e $TMPFILE ]]; then
error "No matching objects found."
error "No matching ${whattolist}s found."
rv=1
elif grep -q "no results" $TMPFILE; then
error "No ${whattolist}s found matching '$obname'."
@ -1879,6 +1986,71 @@ debug "tmpfile contents: [$(cat $TMPFILE)]"
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:"
newtype=""
while [[ -z $newtype ]]; 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
newtype="${o_arr[$retstr]}"
newtype_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
newtype="$this"
newtype_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"
newtype=""
elif [[ $matched -gt 1 ]]; then
error "'$retstr' matched multiple choices: $allmatches"
newtype=""
fi
fi
fi
done
else
newtype="$allobs"
newtype_uuid="$alluuids"
fi
if [[ -z $newtype ]]; then
confirm=0
else
notify_nodots "Adding a new ${BOLD}$newtype${PLAIN}${PURPLE} named $BOLD$newname${PLAIN}"
confirm=1
fi
else
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}\"}"
@ -1898,7 +2070,19 @@ debug "tmpfile contents: [$(cat $TMPFILE)]"
fi
if [[ $confirm -eq 1 ]]; then
actiontargets=$(echo "$data")
if [[ $actionname == "add" ]]; then
# We use alternate values for the actiontarget string here:
# loc=servername (normal)
# ob=name of new ob to add
# obuuid=uuid of model
# extrainfo=curl post data
actiontargets="$curlocs,$newname,$newtype_uuid"
# ooo
#actiontargets="${actiontargets},'{\"name\": \"$newname\", \"node_type\": \"$newtype\", \"compute_id\": \"local\"}'"
actiontargets="${actiontargets},name:$newname^node_type:$newtype^compute_id:local"
else
actiontargets=$(echo "$data")
fi
if [[ $actionname == "connect" ]]; then
local devname sevname srvport
devname=$(echo "$data" | awk -F, '{ print $2 }')
@ -1912,12 +2096,12 @@ debug "tmpfile contents: [$(cat $TMPFILE)]"
rm -f "$TMPFILE"
debug "about to call runaction with:"
debug " whattolist = $whattolist"
debug " obtype = $endpoint"
debug " actionname = $actionname"
debug " actiontargets = $actiontargets"
debug " opts = ${opts[@]}"
debug " outputfile = ${TMPFILE}"
runaction ${whattolist} $actionname "$actiontargets" ${opts[@]} >"$TMPFILE"
runaction ${endpoint} $actionname "$actiontargets" ${opts[@]} >"$TMPFILE"
rv=$?
if [[ $actionname != "connect" ]]; then
ok
@ -2124,7 +2308,7 @@ addendpoint nodes projects/_CURPROJECT_/nodes node node_id name
addepalias nodes n
addeptitles nodes "Node " "Model_UUID" "Status " "Console_Port"
addepfields nodes ".name" ".template_id" ".status" ".console"
addepactions nodes start stop connect
addepactions nodes start stop connect add
addendpoint links projects/_CURPROJECT_/links link link_id link_id
addepalias links l
@ -2167,6 +2351,7 @@ addcmdalias "start" "action node start" ""
addcmdalias "stop" "action node stop" ""
addcmdalias "connect" "action node connect" ""
addcmdalias "c" "action node connect" ""
addcmdalias "add" "action node add" ""
addcmd help "List regular commands" 0 "?" "h"
addcmd exit "Exit from gnscli" 0 quit