1818
1919parse_json () {
2020 local json_string=" $1 "
21- echo " $json_string " | jq ' .' > /dev/null || { echo ' {"error": "Invalid JSON input"}' ; exit 1; }
21+ echo " $json_string " | jq ' .' > /dev/null || { echo ' {"status": " error", "error": "Invalid JSON input"}' ; exit 1; }
2222
2323 local -A details
2424 while IFS=" =" read -r key value; do
@@ -112,9 +112,14 @@ call_proxmox_api() {
112112 curl_opts+=(-d " $data " )
113113 fi
114114
115- # echo curl "${curl_opts[@]}" "https://${url}:8006/api2/json${path}" >&2
116115 response=$( curl " ${curl_opts[@]} " " https://${url} :8006/api2/json${path} " )
116+ local status=$?
117+ if [[ $status -ne 0 ]]; then
118+ echo " {\" errors\" :{\" curl\" :\" API call failed with status $status : $( echo " $response " | jq -Rsa . | jq -r .) \" }}"
119+ return $status
120+ fi
117121 echo " $response "
122+ return 0
118123}
119124
120125wait_for_proxmox_task () {
@@ -129,7 +134,7 @@ wait_for_proxmox_task() {
129134 local now
130135 now=$( date +%s)
131136 if (( now - start_time > timeout )) ; then
132- echo ' {"error":"Timeout while waiting for async task"}'
137+ echo ' {"status": "error", " error":"Timeout while waiting for async task"}'
133138 exit 1
134139 fi
135140
@@ -139,7 +144,7 @@ wait_for_proxmox_task() {
139144 if [[ -z " $status_response " || " $status_response " == * ' "errors":' * ]]; then
140145 local msg
141146 msg=$( echo " $status_response " | jq -r ' .message // "Unknown error"' )
142- echo " {\" error\" : \" $msg \" }"
147+ echo " {\" status \" : \" error\" , \" error \" : \" $msg \" }"
143148 exit 1
144149 fi
145150
@@ -286,85 +291,81 @@ status() {
286291}
287292
288293get_node_host () {
289- check_required_fields node
290- local net_json host
291-
292- if ! net_json=" $( call_proxmox_api GET " /nodes/${node} /network" ) " ; then
293- echo " "
294- return 1
295- fi
296-
297- # Prefer a static non-bridge IP
298- host=" $( echo " $net_json " | jq -r '
299- .data
300- | map(select(
301- (.type // "") != "bridge" and
302- (.type // "") != "bond" and
303- (.method // "") == "static" and
304- ((.address // .cidr // "") != "")
305- ))
306- | map(.address // (.cidr | split("/")[0]))
307- | .[0] // empty
308- ' 2> /dev/null) "
309-
310- # Fallback: first interface with a CIDR
311- if [[ -z " $host " ]]; then
312- host=" $( echo " $net_json " | jq -r '
313- .data
314- | map(select((.cidr // "") != ""))
315- | map(.cidr | split("/")[0])
316- | .[0] // empty
317- ' 2> /dev/null) "
318- fi
319-
320- echo " $host "
321- }
294+ check_required_fields node
295+ local net_json host
296+
297+ if ! net_json=" $( call_proxmox_api GET " /nodes/${node} /network" ) " ; then
298+ echo " "
299+ return 1
300+ fi
301+
302+ # Prefer a static non-bridge IP
303+ host=" $( echo " $net_json " | jq -r '
304+ .data
305+ | map(select(
306+ (.type // "") != "bridge" and
307+ (.type // "") != "bond" and
308+ (.method // "") == "static" and
309+ ((.address // .cidr // "") != "")
310+ ))
311+ | map(.address // (.cidr | split("/")[0]))
312+ | .[0] // empty
313+ ' 2> /dev/null) "
314+
315+ # Fallback: first interface with a CIDR
316+ if [[ -z " $host " ]]; then
317+ host=" $( echo " $net_json " | jq -r '
318+ .data
319+ | map(select((.cidr // "") != ""))
320+ | map(.cidr | split("/")[0])
321+ | .[0] // empty
322+ ' 2> /dev/null) "
323+ fi
324+
325+ echo " $host "
326+ }
322327
323328 get_console () {
324- check_required_fields node vmid
325-
326- # Request VNC proxy from Proxmox
327- local api_resp port ticket
328- if ! api_resp=" $( call_proxmox_api POST " /nodes/${node} /qemu/${vmid} /vncproxy" ) " ; then
329- jq -n --arg msg " API call failed for node=$node vmid=$vmid " \
330- ' {status:"error", message:$msg, code:"API_CALL_FAILED"}'
331- return 1
332- fi
333-
334- port=" $( echo " $api_resp " | jq -re ' .data.port // empty' 2> /dev/null || true) "
335- ticket=" $( echo " $api_resp " | jq -re ' .data.ticket // empty' 2> /dev/null || true) "
336-
337- if [[ -z " $port " || -z " $ticket " ]]; then
338- jq -n --arg msg " Proxmox response missing port/ticket" \
339- --arg raw " $api_resp " \
340- ' {status:"error", message:$msg, code:"BAD_UPSTREAM_RESPONSE", upstream:$raw}'
341- return 1
342- fi
343-
344- # Derive host from node’s network info
345- local host
346- host=" $( get_node_host) "
347- if [[ -z " $host " ]]; then
348- jq -n --arg msg " Could not determine host IP for node $node " \
349- ' {status:"error", message:$msg, code:"HOST_RESOLUTION_ERROR"}'
350- return 1
351- fi
352-
353- # Success JSON to stdout
354- jq -n \
355- --arg host " $host " \
356- --arg port " $port " \
357- --arg password " $ticket " \
358- ' {
359- status: "success",
360- message: "Console retrieved",
361- console: {
362- host: $host,
363- port: $port,
364- password: $password,
365- protocol: "vnc"
366- }
367- }'
329+ check_required_fields node vmid
330+
331+ local api_resp port ticket
332+ if ! api_resp=" $( call_proxmox_api POST " /nodes/${node} /qemu/${vmid} /vncproxy" ) " ; then
333+ echo " $api_resp " | jq -c ' {status:"error", error:(.errors.curl // (.errors|tostring))}'
334+ exit 1
335+ fi
336+
337+ port=" $( echo " $api_resp " | jq -re ' .data.port // empty' 2> /dev/null || true) "
338+ ticket=" $( echo " $api_resp " | jq -re ' .data.ticket // empty' 2> /dev/null || true) "
339+
340+ if [[ -z " $port " || -z " $ticket " ]]; then
341+ jq -n --arg raw " $api_resp " \
342+ ' {status:"error", error:"Proxmox response missing port/ticket", upstream:$raw}'
343+ exit 1
344+ fi
345+
346+ # Derive host from node’s network info
347+ local host
348+ host=" $( get_node_host) "
349+ if [[ -z " $host " ]]; then
350+ jq -n --arg msg " Could not determine host IP for node $node " \
351+ ' {status:"error", error:$msg}'
352+ exit 1
353+ fi
354+
355+ jq -n \
356+ --arg host " $host " \
357+ --arg port " $port " \
358+ --arg password " $ticket " \
359+ ' {
360+ status: "success",
361+ message: "Console retrieved",
362+ console: {
363+ host: $host,
364+ port: $port,
365+ password: $password,
366+ protocol: "vnc"
367+ }
368+ }'
368369 }
369370
370371list_snapshots () {
@@ -438,7 +439,12 @@ parameters_file="$2"
438439wait_time=$3
439440
440441if [[ -z " $action " || -z " $parameters_file " ]]; then
441- echo ' {"error":"Missing required arguments"}'
442+ echo ' {"status": "error", "error": "Missing required arguments"}'
443+ exit 1
444+ fi
445+
446+ if [[ ! -r " $parameters_file " ]]; then
447+ echo ' {"status": "error", "error": "File not found or unreadable"}'
442448 exit 1
443449fi
444450
@@ -479,7 +485,7 @@ case $action in
479485 status
480486 ;;
481487 getconsole)
482- get_console " $parameters "
488+ get_console
483489 ;;
484490 ListSnapshots)
485491 list_snapshots
@@ -494,7 +500,7 @@ case $action in
494500 delete_snapshot
495501 ;;
496502 * )
497- echo ' {"error": "Invalid action"}'
503+ echo ' {"status": " error", "error": "Invalid action"}'
498504 exit 1
499505 ;;
500506esac
0 commit comments