diff --git a/gnscli.sh b/gnscli.sh index 22356dc..9a6d4fc 100755 --- a/gnscli.sh +++ b/gnscli.sh @@ -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="" 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="" + 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 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 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 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