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
Detailed Breakdown
Let’s delve into the script to understand its workings step by step.
- 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.
- 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.
- 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.
- NinjaOne RMM CLI Validation The script checks for the existence of the NinjaOne RMM CLI tool, which is necessary for updating custom fields.
- Node Name Retrieval The script defines a function to retrieve the Proxmox node name, which is required to query specific storage details.
- 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.
- HTML Table Creation The script constructs an HTML table for the WYSIWYG custom field, summarizing the storage status in a tabular format.
- 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.