Linux Script Guide: How to Automate Proxmox VM Information Gathering

In today’s IT landscape, efficient management and monitoring of virtual environments are crucial for system administrators and Managed Service Providers (MSPs). Virtual environments, like those managed by Proxmox, require regular oversight to ensure smooth operation and optimal performance.

Automating the collection of virtual machine (VM) status and basic information not only saves time but also reduces the risk of human error. This blog post explores a bash script designed to fetch and display the status and details of Proxmox guests, demonstrating its utility and how it can streamline IT operations.

Background

Proxmox is a popular open-source virtualization management solution, combining KVM and container-based virtualization in a single platform. For IT professionals and MSPs, monitoring the state of VMs and containers is a routine yet vital task. This script addresses the need for an automated, consistent method to gather and display VM information, presenting it in a user-friendly format that can be easily accessed and interpreted.

The Script

#!/usr/bin/env bash

# Description: This script gets the status and basic info of all Proxmox guests on a host and saves it to a WYSIWYG custom field.
#
# Release Notes: Initial Release
# By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
# Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
# Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
# Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
# Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
# Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
# Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
# EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#
# Below are all the (case sensitive) valid parameters for this script.
# Only the custom field name is required!
# Preset Parameter: "Custom_Field_Name"
#   Custom_Field_Name: The name of the WYSIWYG custom field to save the VM info to.

Custom_Field_Name=$1

if [[ -n "${customFieldName}" ]]; then
    Custom_Field_Name="${customFieldName}"
fi

if [[ -z "${Custom_Field_Name}" || "${Custom_Field_Name}" == "null" ]]; then
    echo "The custom field name is required."
    echo " Example: guests"
    exit 1
fi

# Check that we have the required tools
if ! command -v pvesh &> /dev/null; then
    echo "The Proxmox VE API tool 'pvesh' is required."
    exit 1
fi
if ! command -v python3 &> /dev/null; then
    echo "The python3 is required. Should already be installed."
    exit 1
fi

# Check that we are running as root
if [[ $EUID -ne 0 ]]; then
    echo "This script must be run as root."
    exit 1
fi

function SetCustomField() {
    /opt/NinjaRMMAgent/programdata/ninjarmm-cli "$@"
}

# Get the status and basic info of all Proxmox VMs on a host
qemu_guests=$(pvesh get /nodes/localhost/qemu --output-format=json)

# Create a table to store the VM info with the headers: Name, Status, Memory, CPUs, Disk Sizes
vm_table="<table><tr><th>Status</th><th>ID</th><th>Name</th><th>Memory</th><th>CPUs</th><th>Disk Sizes Combined</th></tr>"

# Loop through each VM and add the info to the table
qemu_table=$(echo "$qemu_guests" | python3 -c '
import sys, json

# Function to convert bytes to human readable format
def human_readable_size(size):
    for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]:
        if size < 1024:
            return f"{size:.2f} {unit}"
        size /= 1024

qemu_guests = json.load(sys.stdin)
vm_table = ""

for qemu in qemu_guests:
    qemu_id = qemu["vmid"]
    qemu_name = qemu["name"]
    qemu_status = qemu["status"]
    # Convert the memory from bytes to GB
    qemu_mem = human_readable_size(qemu["maxmem"])
    qemu_cpus = qemu["cpus"]
    # Convert the disk size from bytes to GB
    qemu_disk = human_readable_size(qemu["maxdisk"])

    # Add HTML blank space if values are empty
    qemu_id = qemu_id if qemu_id else "&nbsp;"
    qemu_name = qemu_name if qemu_name else "&nbsp;"
    qemu_mem = qemu_mem if qemu_mem else "&nbsp;"
    qemu_cpus = qemu_cpus if qemu_cpus else "&nbsp;"
    qemu_disk = qemu_disk if qemu_disk else "&nbsp;"

    if "running" in qemu_status:
        status_text = "<tr class='"'success'"'><td>Running</td>"
    elif "stopped" in qemu_status:
        status_text = "<tr class='"'danger'"'><td>Stopped</td>"
    else:
        status_text = "<tr class='"'other'"'><td>{}</td>".format(qemu_status)

    vm_table += "{}<td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>".format(
        status_text, qemu_id, qemu_name, qemu_mem, qemu_cpus, qemu_disk
    )

print(vm_table)
')
vm_table="$vm_table$qemu_table"

# Loop through each lxc and add the info to the table
lxc_guests=$(pvesh get /nodes/localhost/lxc --output-format=json)
# Loop through each lxc and add the info to the table
lxc_table=$(echo "$lxc_guests" | python3 -c '
import sys, json

# Function to convert bytes to human readable format
def human_readable_size(size):
    for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]:
        if size < 1024:
            return f"{size:.2f} {unit}"
        size /= 1024

lxc_guests = json.load(sys.stdin)
vm_table = ""

for lxc in lxc_guests:
    lxc_id = lxc["vmid"]
    lxc_name = lxc["name"]
    lxc_status = lxc["status"]
    # Convert the memory from bytes to GB
    lxc_mem = human_readable_size(lxc["maxmem"])
    lxc_cpus = lxc["cpus"]
    # Convert the disk size from bytes to GB
    lxc_disk = human_readable_size(lxc["maxdisk"])

    # Add HTML blank space if values are empty
    lxc_id = lxc_id if lxc_id else "&nbsp;"
    lxc_name = lxc_name if lxc_name else "&nbsp;"
    lxc_mem = lxc_mem if lxc_mem else "&nbsp;"
    lxc_cpus = lxc_cpus if lxc_cpus else "&nbsp;"
    lxc_disk = lxc_disk if lxc_disk else "&nbsp;"

    if "running" in lxc_status:
        status_text = "<tr class='"'success'"'><td>Running</td>"
    elif "stopped" in lxc_status:
        status_text = "<tr class='"'danger'"'><td>Stopped</td>"
    else:
        status_text = "<tr class='"'other'"'><td>{}</td>".format(lxc_status)

    vm_table += "{}<td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>".format(
        status_text, lxc_id, lxc_name, lxc_mem, lxc_cpus, lxc_disk
    )

print(vm_table)
')
vm_table="$vm_table$lxc_table"

# Close the table
vm_table="$vm_table</table>"

# Highlight the running and stopped VMs
vm_table=$(echo "$vm_table" | sed 's/<tr><td>running<\/td>/<tr class="success"><td>Running<\/td>/')
vm_table=$(echo "$vm_table" | sed 's/<tr><td>stopped<\/td>/<tr class="danger"><td>Stopped<\/td>/')

# Save the table to the custom field
if ! SetCustomField set "$Custom_Field_Name" "$vm_table"; then
    echo "Failed to save the Proxmox VM info to the custom field: $Custom_Field_Name"
    exit 1
fi
echo "The Proxmox VM info has been saved to the custom field: $Custom_Field_Name"

 

Access over 300+ scripts in the NinjaOne Dojo

Get Access

Detailed Breakdown

The provided bash script retrieves the status and essential information of all Proxmox guests on a host and saves this data to a custom field. This is particularly useful for environments with numerous VMs, where manual checks can be time-consuming and error-prone.

Step-by-Step Explanation

1. Script Initialization and Parameter Handling:

  • The script begins by defining the custom field name, which is a mandatory parameter. This field name will store the VM information.
  • If the custom field name is not provided or is invalid, the script exits with an error message.

2. Tool Availability Check:

  • The script verifies the availability of required tools: pvesh (Proxmox VE API tool) and python3. If these tools are not found, the script exits with an appropriate error message.

3. Root Privileges Verification:

  • The script checks if it is running with root privileges. If not, it exits with an error message.

4. Fetching VM Information:

  • Using pvesh, the script retrieves information about QEMU VMs and LXC containers from the Proxmox host.
  • This information is processed using Python to generate an HTML table with details such as status, ID, name, memory, CPUs, and combined disk sizes.

5. Generating HTML Table:

  • The Python script embedded within the bash script formats the retrieved JSON data into an HTML table. This table is styled to highlight running and stopped VMs differently.

6. Saving the Table to a Custom Field:

  • The generated HTML table is saved to the specified custom field using the NinjaRMM CLI tool.

Potential Use Cases

Imagine an MSP managing multiple Proxmox environments for various clients. Manually checking the status and resource allocation of each VM across different hosts can be cumbersome. By deploying this script, the MSP can automate the collection of this data and have it readily available in a custom field, accessible through their management interface. This not only enhances efficiency but also ensures that they can quickly respond to any issues that arise.

Comparisons

Other methods to gather VM information might involve manually running commands and compiling results, which is time-consuming and prone to errors. Tools like Proxmox’s web interface provide the needed information but require manual navigation and checking. In contrast, this script automates the entire process, ensuring consistency and saving valuable time.

FAQs

Q: What if the script fails to find pvesh or python3?
A: The script checks for these dependencies at the start and exits with a clear error message if they are not found, guiding the user to install the missing tools.

Q: Can the script be run without root privileges?
A: No, the script must be run as root to access the necessary system information.

Q: What if the custom field name is not provided?
A: The script requires the custom field name as a parameter. If it is not provided, the script will exit with an error message.

Implications

Automating the collection of VM information not only improves operational efficiency but also enhances IT security. Regular, automated checks ensure that all VMs are accounted for and running as expected, reducing the risk of unnoticed downtimes or resource misallocations.

Recommendations

When using this script, ensure that:

  • The script is run on a regular schedule to keep the VM information up-to-date.
  • Proper permissions are set for the script to run as root.
  • Dependencies (pvesh, python3, NinjaRMM CLI) are installed and correctly configured.

Final Thoughts

This script is a valuable tool for IT professionals managing Proxmox environments, streamlining the process of gathering and displaying VM information. For those utilizing NinjaOne, this script further integrates into their workflow, making it easier to maintain a clear and updated view of their virtual infrastructure. By automating routine tasks, IT professionals can focus on more strategic activities, enhancing overall productivity and system reliability.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).