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
129 lines
3.2 KiB
Perl
129 lines
3.2 KiB
Perl
#!/usr/bin/env perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Test::More tests => 9;
|
|
use File::Temp qw(tempdir);
|
|
use File::Path qw(make_path);
|
|
|
|
# Mock the command paths for testing
|
|
my $test_dir = tempdir( CLEANUP => 1 );
|
|
my $cmd = {
|
|
multipath => "$test_dir/multipath",
|
|
multipathd => "$test_dir/multipathd",
|
|
blockdev => "$test_dir/blockdev",
|
|
dmsetup => "$test_dir/dmsetup",
|
|
kpartx => "$test_dir/kpartx"
|
|
};
|
|
|
|
# Track if commands were checked
|
|
my $commands_checked = 0;
|
|
|
|
sub ensure_commands_checked {
|
|
return if $commands_checked;
|
|
check_commands();
|
|
$commands_checked = 1;
|
|
}
|
|
|
|
sub get_command_path {
|
|
my ( $name ) = @_;
|
|
|
|
ensure_commands_checked();
|
|
|
|
my $path = $cmd->{ $name };
|
|
if ( !defined $path ) {
|
|
die "Error :: Unknown command '$name'\n";
|
|
}
|
|
|
|
if ( !-x $path ) {
|
|
die "Error :: Command '$name' not found or not executable at '$path'\n";
|
|
}
|
|
|
|
return $path;
|
|
}
|
|
|
|
sub check_commands {
|
|
my @missing;
|
|
|
|
foreach my $name ( keys %$cmd ) {
|
|
my $path = $cmd->{ $name };
|
|
if ( !-x $path ) {
|
|
push @missing, "$name ($path)";
|
|
}
|
|
}
|
|
|
|
if ( @missing ) {
|
|
note "Warning :: The following commands are not available:";
|
|
note " - $_" foreach @missing;
|
|
}
|
|
|
|
return scalar @missing == 0;
|
|
}
|
|
|
|
# Test 1: Unknown command should die
|
|
eval { get_command_path('unknown_command') };
|
|
like( $@, qr/Unknown command/, 'Unknown command throws error' );
|
|
|
|
# Test 2: Non-existent command should die
|
|
eval { get_command_path('multipath') };
|
|
like( $@, qr/not found or not executable/, 'Non-existent command throws error' );
|
|
|
|
# Test 3: Create executable commands
|
|
foreach my $name ( keys %$cmd ) {
|
|
my $path = $cmd->{ $name };
|
|
open my $fh, '>', $path or die "Cannot create $path: $!";
|
|
print $fh "#!/bin/sh\necho 'test'\n";
|
|
close $fh;
|
|
chmod 0755, $path;
|
|
}
|
|
|
|
# Reset check flag to re-run validation
|
|
$commands_checked = 0;
|
|
|
|
# Test 4: Valid command should return path
|
|
my $path = get_command_path('multipath');
|
|
is( $path, $cmd->{multipath}, 'Valid command returns correct path' );
|
|
|
|
# Test 5: Commands should be checked only once
|
|
my $check_count = 0;
|
|
{
|
|
no warnings 'redefine';
|
|
my $original = \&check_commands;
|
|
*check_commands = sub {
|
|
$check_count++;
|
|
$original->();
|
|
};
|
|
|
|
$commands_checked = 0;
|
|
get_command_path('multipath');
|
|
get_command_path('dmsetup');
|
|
get_command_path('kpartx');
|
|
}
|
|
is( $check_count, 1, 'check_commands called only once' );
|
|
|
|
# Test 6: All commands should be validated
|
|
my $result = check_commands();
|
|
ok( $result, 'All commands are valid' );
|
|
|
|
# Test 7: Make one command non-executable
|
|
chmod 0644, $cmd->{kpartx};
|
|
$result = check_commands();
|
|
ok( !$result, 'Non-executable command detected' );
|
|
|
|
# Test 8: Check that non-executable command fails
|
|
eval { get_command_path('kpartx') };
|
|
like( $@, qr/not executable/, 'Non-executable command throws error' );
|
|
|
|
# Test 9: Restore executable and verify it works
|
|
chmod 0755, $cmd->{kpartx};
|
|
$commands_checked = 0;
|
|
$path = get_command_path('kpartx');
|
|
is( $path, $cmd->{kpartx}, 'Restored command works' );
|
|
|
|
# Test 10: Verify all expected commands exist in hash
|
|
my @expected = qw(multipath multipathd blockdev dmsetup kpartx);
|
|
my @actual = sort keys %$cmd;
|
|
is_deeply( \@actual, [sort @expected], 'All expected commands present in hash' );
|
|
|
|
done_testing();
|