Cluster Operations - FreshPerf/PVE4J GitHub Wiki

Cluster Operations

This guide covers cluster-wide operations in PVE4J.

Table of Contents

Cluster Information

Get Cluster Index

import fr.freshperf.pve4j.entities.cluster.PveClusterIndex;
import java.util.List;

try {
    List<PveClusterIndex> index = proxmox.getCluster()
            .getIndex()
            .execute();
    
    for (PveClusterIndex item : index) {
        System.out.println("Available endpoint: " + item);
    }
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Get Cluster Status

import fr.freshperf.pve4j.entities.cluster.PveClusterStatus;
import java.util.List;

try {
    List<PveClusterStatus> status = proxmox.getCluster()
            .getStatus()
            .execute();
    
    for (PveClusterStatus member : status) {
        System.out.println("Name: " + member.getName());
        System.out.println("Type: " + member.getType());
        System.out.println("Online: " + member.getOnline());
        System.out.println("---");
    }
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Cluster Resources

List All Resources

import fr.freshperf.pve4j.entities.cluster.resources.PveClusterResources;
import java.util.List;

try {
    List<PveClusterResources> resources = proxmox.getCluster()
            .getResources()
            .execute();
    
    for (PveClusterResources resource : resources) {
        System.out.println("Type: " + resource.getType());
        System.out.println("ID: " + resource.getId());
        System.out.println("Status: " + resource.getStatus());
        
        if (resource.getVmid() != null) {
            System.out.println("VMID: " + resource.getVmid());
            System.out.println("Name: " + resource.getName());
        }
        
        if (resource.getNode() != null) {
            System.out.println("Node: " + resource.getNode());
        }
        
        System.out.println("---");
    }
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Resource Filtering

Filter by Type: Virtual Machines

try {
    List<PveClusterResources> vms = proxmox.getCluster()
            .getResources("vm")
            .execute();
    
    System.out.println("Total VMs: " + vms.size());
    
    for (PveClusterResources vm : vms) {
        System.out.printf("VMID: %d, Name: %s, Node: %s, Status: %s%n",
                vm.getVmid(), vm.getName(), vm.getNode(), vm.getStatus());
    }
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Filter by Type: Nodes

try {
    List<PveClusterResources> nodes = proxmox.getCluster()
            .getResources("node")
            .execute();
    
    System.out.println("Cluster Nodes: " + nodes.size());
    
    for (PveClusterResources node : nodes) {
        System.out.println("Node: " + node.getNode());
        System.out.println("Status: " + node.getStatus());
        System.out.println("CPU: " + node.getCpu());
        System.out.println("Memory: " + node.getMem() + " / " + node.getMaxmem());
        System.out.println("---");
    }
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Filter by Type: Storage

try {
    List<PveClusterResources> storage = proxmox.getCluster()
            .getResources("storage")
            .execute();
    
    System.out.println("Storage Pools: " + storage.size());
    
    for (PveClusterResources pool : storage) {
        System.out.println("Storage: " + pool.getStorage());
        System.out.println("Node: " + pool.getNode());
        System.out.println("Status: " + pool.getStatus());
        
        if (pool.getDisk() != null && pool.getMaxdisk() != null) {
            double usage = (double) pool.getDisk() / pool.getMaxdisk() * 100;
            System.out.printf("Usage: %.2f%%%n", usage);
        }
        
        System.out.println("---");
    }
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

VMID Management

Get Next Available VMID

try {
    Integer nextId = proxmox.getCluster()
            .getNextId()
            .execute();
    
    System.out.println("Next available VMID: " + nextId);
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Use Next VMID for VM Creation

try {
    Integer vmid = proxmox.getCluster().getNextId().execute();
    
    PveTask task = proxmox.getNodes()
            .get("pve-node-01")
            .getQemu()
            .create(vmid, PveQemuCreateOptions.builder()
                    .name("new-vm")
                    .memory(2048)
                    .cores(2)
                    .build())
            .waitForCompletion(proxmox)
            .execute();
    
    System.out.println("Created VM with VMID: " + vmid);
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

High Availability

PVE4J supports managing Proxmox HA (High Availability) resources.

List HA Resources

import fr.freshperf.pve4j.entities.cluster.ha.PveHaResource;

try {
    List<PveHaResource> resources = proxmox.getCluster()
            .getHa()
            .listResources()
            .execute();
    
    for (PveHaResource resource : resources) {
        System.out.println("HA Resource: " + resource);
    }
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Get a Specific HA Resource

try {
    PveHaResource resource = proxmox.getCluster()
            .getHa()
            .getResource("vm:100")
            .execute();
    
    System.out.println("HA Resource: " + resource);
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Create an HA Resource

try {
    // Simple creation
    proxmox.getCluster()
            .getHa()
            .createResource("vm:100")
            .execute();
    
    System.out.println("HA resource created!");
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Create with Options

import fr.freshperf.pve4j.entities.cluster.ha.PveHaResourceCreateOptions;

try {
    PveHaResourceCreateOptions options = PveHaResourceCreateOptions.builder()
            // configure options as needed
            .build();
    
    proxmox.getCluster()
            .getHa()
            .createResource("vm:100", options)
            .execute();
    
    System.out.println("HA resource created with options!");
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Set HA Resource State

try {
    // Possible states: "started", "stopped", "disabled", "ignored"
    proxmox.getCluster()
            .getHa()
            .setResourceState("vm:100", "started")
            .execute();
    
    System.out.println("HA resource state updated!");
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Delete an HA Resource

try {
    proxmox.getCluster()
            .getHa()
            .deleteResource("vm:100")
            .execute();
    
    System.out.println("HA resource deleted!");
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Resource Monitoring

Cluster-Wide Resource Overview

public class ClusterMonitor {
    
    public void printClusterOverview(Proxmox proxmox) {
        try {
            List<PveClusterResources> resources = proxmox.getCluster()
                    .getResources()
                    .execute();
            
            Map<String, Integer> typeCounts = new HashMap<>();
            
            for (PveClusterResources resource : resources) {
                String type = resource.getType();
                typeCounts.put(type, typeCounts.getOrDefault(type, 0) + 1);
            }
            
            System.out.println("=== Cluster Overview ===");
            typeCounts.forEach((type, count) -> 
                    System.out.println(type + ": " + count));
            
        } catch (ProxmoxAPIError | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Find Resources by Criteria

public List<PveClusterResources> findRunningVMs(Proxmox proxmox) 
        throws ProxmoxAPIError, InterruptedException {
    
    List<PveClusterResources> allVMs = proxmox.getCluster()
            .getResources("vm")
            .execute();
    
    return allVMs.stream()
            .filter(vm -> "running".equals(vm.getStatus()))
            .collect(Collectors.toList());
}

public List<PveClusterResources> findVMsByNode(Proxmox proxmox, String nodeName) 
        throws ProxmoxAPIError, InterruptedException {
    
    List<PveClusterResources> allVMs = proxmox.getCluster()
            .getResources("vm")
            .execute();
    
    return allVMs.stream()
            .filter(vm -> nodeName.equals(vm.getNode()))
            .collect(Collectors.toList());
}

Calculate Cluster Statistics

public class ClusterStats {
    
    public void printClusterStats(Proxmox proxmox) {
        try {
            List<PveClusterResources> vms = proxmox.getCluster()
                    .getResources("vm")
                    .execute();
            
            long runningVMs = vms.stream()
                    .filter(vm -> "running".equals(vm.getStatus()))
                    .count();
            
            long stoppedVMs = vms.stream()
                    .filter(vm -> "stopped".equals(vm.getStatus()))
                    .count();
            
            System.out.println("=== VM Statistics ===");
            System.out.println("Total VMs: " + vms.size());
            System.out.println("Running: " + runningVMs);
            System.out.println("Stopped: " + stoppedVMs);
            
        } catch (ProxmoxAPIError | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Check Cluster Health

public boolean isClusterHealthy(Proxmox proxmox) {
    try {
        List<PveClusterStatus> status = proxmox.getCluster()
                .getStatus()
                .execute();
        
        long onlineNodes = status.stream()
                .filter(member -> Boolean.TRUE.equals(member.getOnline()))
                .count();
        
        System.out.println("Online nodes: " + onlineNodes + "/" + status.size());
        
        return onlineNodes == status.size();
        
    } catch (Exception e) {
        System.err.println("Failed to check cluster health: " + e.getMessage());
        return false;
    }
}

Load Balancing

Find Node with Lowest Load

public String findLeastLoadedNode(Proxmox proxmox) 
        throws ProxmoxAPIError, InterruptedException {
    
    List<PveClusterResources> nodes = proxmox.getCluster()
            .getResources("node")
            .execute();
    
    return nodes.stream()
            .filter(node -> "online".equals(node.getStatus()))
            .min(Comparator.comparingDouble(node -> {
                if (node.getCpu() != null) {
                    return node.getCpu();
                }
                return Double.MAX_VALUE;
            }))
            .map(PveClusterResources::getNode)
            .orElse(null);
}

VM Distribution Across Nodes

public Map<String, Integer> getVMDistribution(Proxmox proxmox) 
        throws ProxmoxAPIError, InterruptedException {
    
    List<PveClusterResources> vms = proxmox.getCluster()
            .getResources("vm")
            .execute();
    
    Map<String, Integer> distribution = new HashMap<>();
    
    for (PveClusterResources vm : vms) {
        String node = vm.getNode();
        if (node != null) {
            distribution.put(node, distribution.getOrDefault(node, 0) + 1);
        }
    }
    
    System.out.println("=== VM Distribution ===");
    distribution.forEach((node, count) -> 
            System.out.println(node + ": " + count + " VMs"));
    
    return distribution;
}

Next Steps