Linux Script Guide: How to Retrieve Proxmox Node Storage Status

Managing storage effectively is a crucial aspect of maintaining robust and efficient IT infrastructure. For IT professionals and Managed Service Providers (MSPs), having tools that provide detailed insights into storage status can greatly enhance their operational efficiency.

One such tool is the bash script designed to retrieve Proxmox node storage status and display the details. This blog post will explore the script’s functionality, its importance, and its application in real-world scenarios.

Background

In a virtualized environment like Proxmox, understanding the status of node storage is vital for performance optimization, troubleshooting, and capacity planning. Proxmox VE (Virtual Environment) is an open-source server virtualization management solution that provides a powerful platform for managing VMs, containers, storage, and networking.

The provided script leverages Proxmox’s API and the NinjaOne RMM CLI tool to gather and present detailed storage information, which can then be saved to custom fields for further analysis or documentation. This script is particularly useful for MSPs who need to monitor multiple client environments and ensure optimal performance and availability.

The Script:

#!/usr/bin/env bash

# Description: Get the details of a Proxmox Node Storage and save it to a multiline and/or WYSIWYG custom field
#
# Release Notes: Fixed 10% width bug.
# 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).

# Command line arguments, swap the numbers if you want the multiline custom field to be the second argument
multiline_custom_field=$1 # First argument is the multiline custom field name
wysiwyg_custom_field=$2   # Second argument is the WYSIWYG custom field name

# Check if the multilineCustomField and wysiwygCustomField are set
if [[ -n "${multilineCustomField}" && "${multilineCustomField}" != "null" ]]; then
    multiline_custom_field=$multilineCustomField
fi
if [[ -n "${wysiwygCustomField}" && "${wysiwygCustomField}" != "null" ]]; then
    wysiwyg_custom_field=$wysiwygCustomField
fi

# Check if the multiline_custom_field and wysiwyg_custom_field are the same
if [[ -n "${multiline_custom_field}" && "${multiline_custom_field}" == "${wysiwyg_custom_field}" ]]; then
    echo "[Error] multilineCustomField and wysiwygCustomField cannot be the same custom field."
    exit 1
fi

# Check if the multiline_custom_field and wysiwyg_custom_field are set
if [[ -z "${multiline_custom_field}" ]]; then
    echo "[Info] multilineCustomField is not set."
fi
if [[ -z "${wysiwyg_custom_field}" ]]; then
    echo "[Info] wysiwygCustomField is not set."
fi

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

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

# Check if ninjarmm-cli command exists
ninjarmm_cli="/opt/NinjaRMMAgent/programdata/ninjarmm-cli"
if [[ -z $ninjarmm_cli ]]; then
    echo "[Error] The ninjarmm-cli command does not exist in the default path. Please ensure the NinjaRMM agent is installed before running this script."
    exit 1
else
    # ninjarmm-cli command exists in the default path
    echo -n
fi

function GetThisNodeName() {
    # Get the node name
    if ! node_name=$(pvesh get /cluster/status --noborder | awk '$6 == 1 {print $2}'); then
        echo "[Error] Failed to get the node name."
        echo "$node_name"
        exit 1
    fi
    echo "$node_name"
}

# Run the pvesh command to get the status information
if ! storages=$(pvesh get /storage --noborder | tail +2); then
    echo "[Error] Failed to get the list of storages."
    echo "$storages"
    exit 1
fi
# Example Output:
# local
# local-zfs
# storage-nas

function formatStorage() {
    echo ""
    echo "Storage Status:"
    # Loop though the storages and get the status of each
    for storage in $storages; do
        # Get the status of the storage
        if ! storage_status=$(pvesh get /storage/"$storage" --noborder); then
            echo "[Error] Failed to get the Storage Status of $storage."
            echo "$storage_status"
            exit 1
        fi
        storage_node=$(GetThisNodeName)
        # Get the storage name
        storage_name=$(echo "$storage_status" | grep -P 'storage\s+' | awk '{print $2}')
        # Get the free space
        # "$storage_name " is used to avoid matching "local-zfs" when searching for "local"
        storage_free_space=$(pvesh get "/nodes/$storage_node/storage" --noborder | grep -P "$storage_name " | awk '{print $5" "$6}')
        # Get the total space
        storage_total_space=$(pvesh get "/nodes/$storage_node/storage" --noborder | grep -P "$storage_name " | awk '{print $9" "$10}')
        echo -n
        echo ""
        echo "$storage"
        echo "-------------"
        # Take the output of $storage_status, skip the first line, then use a colon as a separator between the key and value
        echo "$storage_status" | tail +2 | awk '{print $1 ": " $2}'
        echo "Free: $storage_free_space"
        echo "Total: $storage_total_space"
    done
}
multiline_output=$(formatStorage)

# Create Storage Status label
storage_table="<h2>Storage Status</h2>"
# Create the Storage Status table
storage_table+="<table style='white-space:nowrap;'><tr><th>Storage Name</th><th>Type</th><th>Path/File System</th><th>Free Space</th><th>Total Space</th><th>Content</th></tr>"

# Loop though the storages and get the status of each
for storage in $storages; do
    if ! storage_status=$(pvesh get /storage/"$storage" --noborder); then
        echo "[Error] Failed to get the Storage Status of $storage."
        echo "$storage_status"
        exit 1
    fi
    # Example Output:
    # key     value
    # content images,rootdir
    # digest  c14cb4c9bbcf9a062fa8a82b10afe01cb1ed5b8d
    # pool    rpool/data
    # sparse  1
    # storage local-zfs
    # type    zfspool
    storage_node=$(GetThisNodeName)
    # Get the storage name
    storage_name=$(echo "$storage_status" | grep -P 'storage\s+' | awk '{print $2}')
    # Get the storage type
    storage_type=$(echo "$storage_status" | grep -P 'type\s+' | awk '{print $2}')
    # Get the storage pool/path
    storage_pool=$(echo "$storage_status" | grep -P 'pool\s+' | awk '{print $2}')
    if [[ -z "${storage_pool}" ]]; then
        storage_pool=$(echo "$storage_status" | grep -P 'path\s+' | awk '{print $2}')
    fi
    # Get the storage content
    storage_content=$(echo "$storage_status" | grep -P 'content\s+' | awk '{print $2}')
    # Get the free space
    # "$storage_name " is used to avoid matching "local-zfs" when searching for "local"
    storage_free_space=$(pvesh get "/nodes/$storage_node/storage" --noborder | grep -P "$storage_name " | awk '{print $5" "$6}')
    # Get the total space
    storage_total_space=$(pvesh get "/nodes/$storage_node/storage" --noborder | grep -P "$storage_name " | awk '{print $9" "$10}')

    # Add to the Storage Status table
    storage_table+="<tr><td>$storage_name</td><td>$storage_type</td><td>$storage_pool</td><td>$storage_free_space</td><td>$storage_total_space</td><td>$storage_content</td></tr>"
done

# Close the Storage Status table
storage_table+="</table>"

# Save the results
result_table="$storage_table"

_exit_code=0
# Save the result to the custom field
if [[ -n "$wysiwyg_custom_field" ]]; then
    if [[ -x "$ninjarmm_cli" ]]; then
        if hideOutput=$(echo "$result_table" | "$ninjarmm_cli" set --stdin "$wysiwyg_custom_field" 2>&1); then
            echo "[Info] Successfully set custom field: $wysiwyg_custom_field"
        else
            echo "[Error] Failed to set custom field: $wysiwyg_custom_field. Custom Field does not exit or does not have write permissions."
            _exit_code=1
        fi
    else
        echo "[Error] NinjaRMM CLI not found or not executable"
        _exit_code=1
    fi
fi

if [[ -n "$multiline_custom_field" ]]; then
    if [[ -x "$ninjarmm_cli" ]]; then
        if hideOutput=$(echo "$multiline_output" | "$ninjarmm_cli" set --stdin "$multiline_custom_field" 2>&1); then
            echo "[Info] Successfully set custom field: $multiline_custom_field"
        else
            echo "[Error] Failed to set custom field: $multiline_custom_field. Custom Field does not exit or does not have write permissions."
            _exit_code=1
        fi
    else
        echo "[Error] NinjaRMM CLI not found or not executable"
        _exit_code=1
    fi
fi

# Output the result if no custom fields are set
if [[ -z "${wysiwyg_custom_field}" ]] && [[ -z "${multiline_custom_field}" ]]; then
    # Output the result to the Activity Feed
    echo "${multiline_output}"
fi

if [[ $_exit_code -eq 1 ]]; then
    exit 1
fi

 

Access over 300+ scripts in the NinjaOne Dojo

Get Access

Detailed Breakdown

Let’s delve into the script to understand its workings step by step.

  1. Initialization and Argument Parsing The script begins by parsing command-line arguments to determine the names of the custom fields where the storage details will be stored. It accepts two arguments: one for a multiline custom field and another for a WYSIWYG custom field. These fields are used to store formatted storage information for easier reading and further analysis.
  2. Custom Field Validation The script checks if the custom fields are set through environment variables or command-line arguments. It ensures that both fields are not the same to prevent conflicts.
  3. Tool Availability and Permissions Check The script verifies the availability of the pvesh command, which is used to interact with the Proxmox API, and ensures it is run with root privileges.
  4. NinjaOne RMM CLI Validation The script checks for the existence of the NinjaOne RMM CLI tool, which is necessary for updating custom fields.
  5. Node Name Retrieval The script defines a function to retrieve the Proxmox node name, which is required to query specific storage details.
  6. Storage Information Retrieval and Formatting The script fetches the storage list and iterates over each storage item to gather detailed status information, including free and total space. This information is formatted for both multiline and WYSIWYG custom fields.
  7. HTML Table Creation The script constructs an HTML table for the WYSIWYG custom field, summarizing the storage status in a tabular format.
  8. Saving Results Finally, the script saves the formatted storage information to the specified custom fields using the NinjaOne RMM CLI tool.

Potential Use Cases

Imagine an MSP managing multiple client environments with Proxmox. They need to regularly check the storage status to ensure there’s enough free space for backups and VM operations. Using this script, the MSP can automate the retrieval of storage information and save it to custom fields for each client, enabling quick access to critical data without manual intervention. This automation reduces the risk of human error and ensures timely updates on storage health.

Comparisons

While this script offers a tailored solution for Proxmox environments integrated with NinjaOne RMM, other methods to retrieve storage information include using native Proxmox tools like the web interface or custom scripts without NinjaOne RMM integration.

However, these methods may lack the automation and centralized management features provided by the combination of this script and NinjaOne RMM, making them less efficient for MSPs managing multiple environments.

FAQs

What is Proxmox VE?

Proxmox VE is an open-source server virtualization management platform that allows the management of VMs, containers, storage, and networking.

What is NinjaOne RMM?

NinjaOne RMM is a remote monitoring and management (RMM) tool that helps MSPs and IT professionals manage client environments from a centralized platform.

Do I need root access to run this script?

Yes, root access is required to retrieve storage information from Proxmox nodes.

Can this script be used without NinjaOne RMM?

The script is designed to integrate with NinjaOne RMM for storing custom field data. Without NinjaOne RMM, it can still retrieve and display storage information but won’t save it to custom fields.

Implications

Automating the retrieval and documentation of storage status enhances operational efficiency and reduces the risk of storage-related issues going unnoticed. This proactive approach to storage management can prevent downtime and ensure that IT infrastructure remains healthy and performant.

Recommendations

  • Ensure that the Proxmox API tool (pvesh) and the NinjaOne RMM CLI tool are correctly installed and configured before running the script.
  • Regularly review and update custom fields to keep storage information current and accurate.
  • Test the script in a non-production environment to ensure it meets your needs and integrates seamlessly with your existing processes.

Final Thoughts

Leveraging automation scripts like this one can significantly enhance the efficiency of IT operations, particularly for MSPs managing multiple client environments. NinjaOne, with its powerful RMM capabilities, provides an excellent platform for integrating such scripts, offering a centralized and streamlined approach to IT management. By utilizing these tools, IT professionals can ensure their infrastructure is always running optimally and be better prepared to handle any storage-related challenges that arise.

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

Watch Demo×
×

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).