@@ -64,7 +64,7 @@ parse_json() {
6464 token=" ${host_token:- $extension_token } "
6565 secret=" ${host_secret:- $extension_secret } "
6666
67- check_required_fields vm_internal_name url user token secret node
67+ check_required_fields url user token secret node
6868}
6969
7070urlencode () {
@@ -206,6 +206,10 @@ prepare() {
206206
207207create () {
208208 if [[ -z " $vm_name " ]]; then
209+ if [[ -z " $vm_internal_name " ]]; then
210+ echo ' {"error":"Missing required fields: vm_internal_name"}'
211+ exit 1
212+ fi
209213 vm_name=" $vm_internal_name "
210214 fi
211215 validate_name " VM" " $vm_name "
@@ -331,71 +335,102 @@ get_node_host() {
331335 echo " $host "
332336}
333337
334- get_console () {
335- check_required_fields node vmid
336-
337- local api_resp port ticket
338- if ! api_resp=" $( call_proxmox_api POST " /nodes/${node} /qemu/${vmid} /vncproxy" ) " ; then
339- echo " $api_resp " | jq -c ' {status:"error", error:(.errors.curl // (.errors|tostring))}'
340- exit 1
341- fi
342-
343- port=" $( echo " $api_resp " | jq -re ' .data.port // empty' 2> /dev/null || true) "
344- ticket=" $( echo " $api_resp " | jq -re ' .data.ticket // empty' 2> /dev/null || true) "
345-
346- if [[ -z " $port " || -z " $ticket " ]]; then
347- jq -n --arg raw " $api_resp " \
348- ' {status:"error", error:"Proxmox response missing port/ticket", upstream:$raw}'
349- exit 1
350- fi
351-
352- # Derive host from node’s network info
353- local host
354- host=" $( get_node_host) "
355- if [[ -z " $host " ]]; then
356- jq -n --arg msg " Could not determine host IP for node $node " \
357- ' {status:"error", error:$msg}'
358- exit 1
359- fi
360-
361- jq -n \
362- --arg host " $host " \
363- --arg port " $port " \
364- --arg password " $ticket " \
365- --argjson passwordonetimeuseonly true \
366- ' {
367- status: "success",
368- message: "Console retrieved",
369- console: {
370- host: $host,
371- port: $port,
372- password: $password,
373- passwordonetimeuseonly: $passwordonetimeuseonly,
374- protocol: "vnc"
375- }
376- }'
377- }
338+ get_console () {
339+ check_required_fields node vmid
378340
379- list_snapshots () {
380- snapshot_response=$( call_proxmox_api GET " /nodes/${node} /qemu/${vmid} /snapshot" )
381- echo " $snapshot_response " | jq '
382- def to_date:
383- if . == "-" then "-"
384- elif . == null then "-"
385- else (. | tonumber | strftime("%Y-%m-%d %H:%M:%S"))
386- end;
341+ local api_resp port ticket
342+ if ! api_resp=" $( call_proxmox_api POST " /nodes/${node} /qemu/${vmid} /vncproxy" ) " ; then
343+ echo " $api_resp " | jq -c ' {status:"error", error:(.errors.curl // (.errors|tostring))}'
344+ exit 1
345+ fi
346+
347+ port=" $( echo " $api_resp " | jq -re ' .data.port // empty' 2> /dev/null || true) "
348+ ticket=" $( echo " $api_resp " | jq -re ' .data.ticket // empty' 2> /dev/null || true) "
349+
350+ if [[ -z " $port " || -z " $ticket " ]]; then
351+ jq -n --arg raw " $api_resp " \
352+ ' {status:"error", error:"Proxmox response missing port/ticket", upstream:$raw}'
353+ exit 1
354+ fi
355+
356+ # Derive host from node’s network info
357+ local host
358+ host=" $( get_node_host) "
359+ if [[ -z " $host " ]]; then
360+ jq -n --arg msg " Could not determine host IP for node $node " \
361+ ' {status:"error", error:$msg}'
362+ exit 1
363+ fi
364+
365+ jq -n \
366+ --arg host " $host " \
367+ --arg port " $port " \
368+ --arg password " $ticket " \
369+ --argjson passwordonetimeuseonly true \
370+ ' {
371+ status: "success",
372+ message: "Console retrieved",
373+ console: {
374+ host: $host,
375+ port: $port,
376+ password: $password,
377+ passwordonetimeuseonly: $passwordonetimeuseonly,
378+ protocol: "vnc"
379+ }
380+ }'
381+ }
382+
383+ statuses () {
384+ local response
385+ response=$( call_proxmox_api GET " /nodes/${node} /qemu" )
386+
387+ if [[ -z " $response " ]]; then
388+ echo ' {"status":"error","message":"empty response from Proxmox API"}'
389+ return 1
390+ fi
391+
392+ if ! echo " $response " | jq empty > /dev/null 2>&1 ; then
393+ echo ' {"status":"error","message":"invalid JSON response from Proxmox API"}'
394+ return 1
395+ fi
396+
397+ echo " $response " | jq -c '
398+ def map_state(s):
399+ if s=="running" then "poweron"
400+ elif s=="stopped" then "poweroff"
401+ else "unknown" end;
387402
388403 {
389404 status: "success",
390- printmessage: "true",
391- message: [.data[] | {
392- name: .name,
393- snaptime: ((.snaptime // "-") | to_date),
394- description: .description,
395- parent: (.parent // "-"),
396- vmstate: (.vmstate // "-")
397- }]
398- }
405+ power_state: (
406+ .data
407+ | map(select(.template != 1))
408+ | map({ ( (.name // (.vmid|tostring)) ): map_state(.status) })
409+ | add // {}
410+ )
411+ }'
412+ }
413+
414+ list_snapshots () {
415+ snapshot_response=$( call_proxmox_api GET " /nodes/${node} /qemu/${vmid} /snapshot" )
416+ echo " $snapshot_response " | jq '
417+ def to_date:
418+ if . == "-" then "-"
419+ elif . == null then "-"
420+ else (. | tonumber | strftime("%Y-%m-%d %H:%M:%S"))
421+ end;
422+
423+ {
424+ status: "success",
425+ printmessage: "true",
426+ message: [.data[] | {
427+ name: .name,
428+ snaptime: ((.snaptime // "-") | to_date),
429+ description: .description,
430+ parent: (.parent // "-"),
431+ vmstate: (.vmstate // "-")
432+ }]
433+ }
399434 '
400435}
401436
@@ -463,9 +498,9 @@ parse_json "$parameters" || exit 1
463498
464499cleanup_vm=0
465500cleanup () {
466- if (( cleanup_vm == 1 )) ; then
467- execute_and_wait DELETE " /nodes/${node} /qemu/${vmid} "
468- fi
501+ if (( cleanup_vm == 1 )) ; then
502+ execute_and_wait DELETE " /nodes/${node} /qemu/${vmid} "
503+ fi
469504}
470505
471506trap cleanup EXIT
@@ -492,6 +527,9 @@ case $action in
492527 status)
493528 status
494529 ;;
530+ statuses)
531+ statuses
532+ ;;
495533 getconsole)
496534 get_console
497535 ;;
0 commit comments