Request API - FreshPerf/PVE4J GitHub Wiki

Request API

This guide explains the fluent request API in PVE4J.

Table of Contents

ProxmoxRequest

All PVE4J API calls return a ProxmoxRequest<T> object, which provides a fluent interface for configuring and executing requests.

Basic Structure

ProxmoxRequest<PveVersion> request = proxmox.getVersion();
PveVersion version = request.execute();

Fluent Chaining

PveTask task = proxmox.getNodes()
        .get("pve-node-01")
        .getQemu()
        .get(100)
        .start()
        .waitForCompletion(proxmox)
        .execute();

Request Execution

Simple Execution

Execute the request immediately:

try {
    PveVersion version = proxmox.getVersion().execute();
    System.out.println("Version: " + version.getVersion());
} catch (ProxmoxAPIError | InterruptedException e) {
    e.printStackTrace();
}

Deferred Execution

Store the request and execute later:

ProxmoxRequest<PveVersion> versionRequest = proxmox.getVersion();

// Later...
PveVersion version = versionRequest.execute();

Retry Configuration

PVE4J supports automatic retries for transient failures.

Basic Retry

PveVersion version = proxmox.getVersion()
        .retry(3)  // Retry up to 3 times on failure
        .execute();

Retry with Custom Delay

import java.time.Duration;

PveVersion version = proxmox.getVersion()
        .retry(3)
        .retryDelay(2000)  // Wait 2 seconds between retries
        .execute();

// Or using Duration
PveVersion version = proxmox.getVersion()
        .retry(3)
        .retryDelay(Duration.ofSeconds(5))
        .execute();

Retries are automatically triggered for:

  • HTTP 429 (Too Many Requests)
  • HTTP 503 (Service Unavailable)
  • HTTP 5xx (Server Errors)

Task Transformers

For operations that return tasks, PVE4J provides transformation options.

Wait for Completion

Block until the task completes:

PveTask task = proxmox.getNodes()
        .get("pve-node-01")
        .getQemu()
        .get(100)
        .start()
        .waitForCompletion(proxmox)
        .execute();

// Task is guaranteed to be completed here

Custom Task Polling Interval

By default, task status is checked every second. You can customize this:

import java.time.Duration;

PveTask task = proxmox.getNodes()
        .get("pve-node-01")
        .getQemu()
        .get(100)
        .start()
        .waitForCompletion(proxmox)
        .taskCheckDelay(5000)  // Check every 5 seconds
        .execute();

// Or using Duration
PveTask task = proxmox.getNodes()
        .get("pve-node-01")
        .getQemu()
        .get(100)
        .cloneVm(200)
        .waitForCompletion(proxmox)
        .taskCheckDelay(Duration.ofSeconds(10))  // Check every 10 seconds for long operations
        .execute();

Task Timeout

Set a maximum time to wait for task completion:

PveTask task = proxmox.getNodes()
        .get("pve-node-01")
        .getQemu()
        .get(100)
        .cloneVm(200)
        .waitForCompletion(proxmox)
        .taskTimeout(Duration.ofMinutes(5))
        .taskCheckDelay(Duration.ofSeconds(2))
        .execute();

Asynchronous Callback

Execute a callback when the task completes:

proxmox.getNodes()
        .get("pve-node-01")
        .getQemu()
        .get(100)
        .start()
        .onCompletion((task, status) -> {
            if (status.isSuccessful()) {
                System.out.println("Task completed successfully!");
            } else {
                System.err.println("Task failed: " + status.getExitstatus());
            }
        }, proxmox)
        .execute();

// Continues immediately while task runs in background

Static Wait for Completion

You can also wait for a task after execution using the static method:

import fr.freshperf.pve4j.request.ProxmoxRequest;

PveTask task = vm.start().execute();

// Wait for the task with default 1 second polling
ProxmoxRequest.waitForCompletion(proxmox, task);

// Or with custom polling interval
ProxmoxRequest.waitForCompletion(proxmox, task, 5000);  // 5 second polling

// Or with Duration and timeout
ProxmoxRequest.waitForCompletion(proxmox, task, Duration.ofSeconds(2), Duration.ofMinutes(5));

Request Patterns

Pattern 1: Immediate Execution

// Execute immediately
PveVersion version = proxmox.getVersion().execute();

Use case: Quick operations where you need the result immediately.

Pattern 2: Conditional Execution

ProxmoxRequest<PveQemuStatus> statusRequest = vm.getStatus();

if (someCondition) {
    PveQemuStatus status = statusRequest.execute();
    // Use status
}

Use case: Execute based on runtime conditions.

Pattern 3: Batch Preparation

List<ProxmoxRequest<PveQemuStatus>> requests = new ArrayList<>();

for (int vmid : vmids) {
    requests.add(proxmox.getNodes()
            .get("pve-node-01")
            .getQemu()
            .get(vmid)
            .getStatus());
}

// Execute all requests
for (ProxmoxRequest<PveQemuStatus> request : requests) {
    PveQemuStatus status = request.execute();
    // Process status
}

Use case: Prepare multiple requests and execute in batch.

Pattern 4: Error Handling Chain

try {
    PveVersion version = proxmox.getVersion().execute();
    List<PveNodesIndex> nodes = proxmox.getNodes().getIndex().execute();
    // Continue with more operations
} catch (ProxmoxAPIError e) {
    // Handle all errors in one place
    System.err.println("API Error: " + e.getMessage());
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

Use case: Chain multiple operations with unified error handling.

Advanced Request Handling

Parallel Execution

Execute multiple requests in parallel using streams:

import java.util.concurrent.*;
import java.util.stream.*;

ExecutorService executor = Executors.newFixedThreadPool(5);

List<Integer> vmids = Arrays.asList(100, 101, 102, 103, 104);

List<CompletableFuture<PveQemuStatus>> futures = vmids.stream()
    .map(vmid -> CompletableFuture.supplyAsync(() -> {
        try {
            return proxmox.getNodes()
                    .get("pve-node-01")
                    .getQemu()
                    .get(vmid)
                    .getStatus()
                    .execute();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }, executor))
    .collect(Collectors.toList());

// Wait for all to complete
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

// Get results
List<PveQemuStatus> statuses = futures.stream()
    .map(CompletableFuture::join)
    .collect(Collectors.toList());

executor.shutdown();

Request Composition

Compose multiple requests into a workflow:

public PveQemuStatus ensureVMRunning(Proxmox proxmox, String node, int vmid) 
        throws ProxmoxAPIError, InterruptedException {
    
    // Get current status
    PveQemuStatus status = proxmox.getNodes()
            .get(node)
            .getQemu()
            .get(vmid)
            .getStatus()
            .execute();
    
    // Start if not running
    if (!"running".equals(status.getStatus())) {
        proxmox.getNodes()
                .get(node)
                .getQemu()
                .get(vmid)
                .start()
                .waitForCompletion(proxmox)
                .execute();
        
        // Get updated status
        status = proxmox.getNodes()
                .get(node)
                .getQemu()
                .get(vmid)
                .getStatus()
                .execute();
    }
    
    return status;
}

Conditional Request Chains

public class VMWorkflow {
    
    public void deployVM(Proxmox proxmox, int templateId, int newVmid) 
            throws ProxmoxAPIError, InterruptedException {
        
        // Clone from template
        proxmox.getNodes()
                .get("pve-node-01")
                .getQemu()
                .get(templateId)
                .cloneVm(newVmid)
                .waitForCompletion(proxmox)
                .execute();
        
        // Update configuration
        PveQemuConfigUpdateOptions config = PveQemuConfigUpdateOptions.builder()
                .memory(4096)
                .cores(2)
                .build();
        
        proxmox.getNodes()
                .get("pve-node-01")
                .getQemu()
                .get(newVmid)
                .updateConfig(config)
                .waitForCompletion(proxmox)
                .execute();
        
        // Start the VM
        proxmox.getNodes()
                .get("pve-node-01")
                .getQemu()
                .get(newVmid)
                .start()
                .waitForCompletion(proxmox)
                .execute();
        
        System.out.println("VM " + newVmid + " deployed successfully");
    }
}

Reuse Request Objects

// Define request once
ProxmoxRequest<PveQemuStatus> statusRequest = vm.getStatus();

// Execute multiple times if needed
PveQemuStatus status1 = statusRequest.execute();
Thread.sleep(5000);
PveQemuStatus status2 = statusRequest.execute();

Request Lifecycle

1. Request Creation
   ↓
2. Configuration (optional)
   - retry() / retryDelay()
   - waitForCompletion() / taskTimeout() / taskCheckDelay()
   - onCompletion()
   ↓
3. Execution
   - execute()
   ↓
4. HTTP Request
   ↓
5. Response Processing
   ↓
6. Result/Exception

Next Steps

⚠️ **GitHub.com Fallback** ⚠️