mirror of
https://github.com/kolesa-team/pve-purestorage-plugin.git
synced 2026-08-12 21:53:06 -06:00
f9f8eed94b
feat: add Active Cluster support and improve plugin stability ## Major Features ### Active Cluster Support (Experimental) (#42) - Add support for multiple PureStorage arrays in Active Cluster configuration - Automatic volume connection on all arrays for high availability - Configure via comma-separated addresses and tokens ### Pod Quota Limit Support (#69) - Add proper handling of pod quota_limit parameter - Use quota_limit when set, fall back to array capacity when unlimited - Fix capacity reporting for pods with quotas ### Session Token Caching - Implement session token caching in /etc/pve/priv/purestorage/ - Automatic token refresh at 80% of TTL to prevent expiration - In-memory and file-based caching with jitter to prevent thundering herd ### Debug Logging - Add configurable debug logging with 4 levels (0-3) - Support both config parameter and PURESTORAGE_DEBUG environment variable ## Bug Fixes - Fix volume deletion when connected to multiple hosts - Query all connections before destroy - Disconnect from all hosts on all arrays - Prevents "Cannot destroy volume because it is currently connected" error ## CI/CD Improvements - Add workflow_dispatch trigger to checks workflow - Add option to check all files or only changed files - Add comprehensive markdown linting with markdownlint-cli2 ## Testing - Add token caching tests (tests/token_cache_test.pl) - Test token validation, expiration, and race conditions - Test cleanup of expired cache files ## Refactoring (#72) - Refactor volume removal logic to handle multiple host connections - Improve device cleanup sequence (LVM, partitions, multipath) - Extract connection querying logic before volume destruction - Refactor CI/CD workflows for better maintainability and flexibility - Improve error handling and logging throughout the plugin - Enhance Active Cluster support with proper multi-array operations ## Code Formatting - Format all Perl files with perltidy using .perltidyrc configuration - Ensure consistent code style across the codebase - Fix formatting issues in PureStoragePlugin.pm and test files ## Documentation - Update README with new functionality
142 lines
2.9 KiB
Perl
142 lines
2.9 KiB
Perl
#!/usr/bin/env perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Test::More tests => 8;
|
|
|
|
# Mock HTTP response
|
|
package MockHTTPResponse {
|
|
sub new {
|
|
my ( $class, $code, $success ) = @_;
|
|
return bless { code => $code, success => $success }, $class;
|
|
}
|
|
sub code { $_[0]->{code} }
|
|
sub is_success { $_[0]->{success} }
|
|
}
|
|
|
|
# Test retry counter logic
|
|
my $retry_count = 0;
|
|
my $max_retries = 1;
|
|
my @responses;
|
|
|
|
sub simulate_request {
|
|
my $response = shift @responses;
|
|
return $response;
|
|
}
|
|
|
|
# Test 1: Success on first try (no retry)
|
|
@responses = ( MockHTTPResponse->new(200, 1) );
|
|
$retry_count = 0;
|
|
|
|
while ( $retry_count <= $max_retries ) {
|
|
my $response = simulate_request();
|
|
|
|
if ( $response->code == 401 ) {
|
|
$retry_count++;
|
|
if ( $retry_count <= $max_retries ) {
|
|
next; # Retry
|
|
}
|
|
}
|
|
last; # Success or max retries
|
|
}
|
|
|
|
is( $retry_count, 0, 'No retry on successful response' );
|
|
|
|
# Test 2: One retry on 401, then success
|
|
@responses = (
|
|
MockHTTPResponse->new(401, 0),
|
|
MockHTTPResponse->new(200, 1)
|
|
);
|
|
$retry_count = 0;
|
|
|
|
while ( $retry_count <= $max_retries ) {
|
|
my $response = simulate_request();
|
|
|
|
if ( $response->code == 401 ) {
|
|
$retry_count++;
|
|
if ( $retry_count <= $max_retries ) {
|
|
next;
|
|
}
|
|
}
|
|
last;
|
|
}
|
|
|
|
is( $retry_count, 1, 'One retry on 401 response' );
|
|
|
|
# Test 3: Max retries reached (401 twice)
|
|
@responses = (
|
|
MockHTTPResponse->new(401, 0),
|
|
MockHTTPResponse->new(401, 0)
|
|
);
|
|
$retry_count = 0;
|
|
|
|
while ( $retry_count <= $max_retries ) {
|
|
my $response = simulate_request();
|
|
|
|
if ( $response->code == 401 ) {
|
|
$retry_count++;
|
|
if ( $retry_count <= $max_retries ) {
|
|
next;
|
|
} else {
|
|
last; # Max retries
|
|
}
|
|
}
|
|
last;
|
|
}
|
|
|
|
is( $retry_count, 2, 'Max retries (2) attempted on repeated 401' );
|
|
|
|
# Test 4: Loop exits after max retries
|
|
ok( $retry_count > $max_retries, 'Retry count exceeds max_retries after exhausting' );
|
|
|
|
# Test 5: No retry on non-401 errors
|
|
@responses = ( MockHTTPResponse->new(500, 0) );
|
|
$retry_count = 0;
|
|
|
|
while ( $retry_count <= $max_retries ) {
|
|
my $response = simulate_request();
|
|
|
|
if ( $response->code == 401 ) {
|
|
$retry_count++;
|
|
if ( $retry_count <= $max_retries ) {
|
|
next;
|
|
}
|
|
}
|
|
last;
|
|
}
|
|
|
|
is( $retry_count, 0, 'No retry on 500 error' );
|
|
|
|
# Test 6: Retry counter increments correctly
|
|
my @counts;
|
|
@responses = (
|
|
MockHTTPResponse->new(401, 0),
|
|
MockHTTPResponse->new(401, 0),
|
|
MockHTTPResponse->new(200, 1)
|
|
);
|
|
$retry_count = 0;
|
|
|
|
while ( $retry_count <= $max_retries ) {
|
|
push @counts, $retry_count;
|
|
my $response = simulate_request();
|
|
|
|
if ( $response->code == 401 ) {
|
|
$retry_count++;
|
|
if ( $retry_count <= $max_retries ) {
|
|
next;
|
|
}
|
|
}
|
|
last;
|
|
}
|
|
|
|
is_deeply( \@counts, [0, 1], 'Retry counter increments: 0, 1' );
|
|
|
|
# Test 7: Max retries = 1 allows exactly 1 retry
|
|
is( $max_retries, 1, 'Max retries configured to 1' );
|
|
|
|
# Test 8: Total attempts = max_retries + 1
|
|
my $total_attempts = $max_retries + 1;
|
|
is( $total_attempts, 2, 'Total attempts = 2 (initial + 1 retry)' );
|
|
|
|
done_testing();
|