Convert direct print statements to use the logger for consistent info message handling.
Also convert warn and die calls to log with the common logger for unified logging.
Removes repetition, enables logging to syslog which allows each message to be timestamped, and can more easily compare
with other systemctl logs like multipathd and iscsid daemons and proxmox services to make it easier to identify race
conditions.
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
Pure currently does not support direct mounting of snapshots.
As we currently silently ignore the snapname field at least error
out if we receive a non empty snapname. Its unclear if this is
still used as vzdump nowadays does live backups.
Signed-off-by: Peter Lieven <pl@dlhnet.de>
Eliminate scsi_rescan_device()
Add get_device_path_wwn()
Add device_op() to serve as helper for device operations
In scsi_scan_new()
* Use device_op()
In purestorage_get_device_size()
* Rename to get_device_size()
* Drop $class
In remove_block_device()
* Rename it to block_device_action()
* Use common code to remove or rescan devices
* Use device_op() helper to perform a device action
Add block_device_slaves() returning resolved device path and its slaves
In purestorage_get_wwn()
* Use get_device_path_wwn() to simplify the code
Redesign purestorage_resize_volume()
* Avoid extra API call by using volume serial returned by volume resize action
* Use get_device_path_wwn()
* Remove unneeded protocol checks
* Support [unlikely] case when resized volume is not mapped/connected
* Use block_device_slaves() and block_device_action() to simplify the code
Redesign unmap_volume()
* Use block_device_slaves() and block_device_action() to simplify the code
In scsi_scan_new()
* Pass protocol as parameter
* Adjust code to scan hosts for specified protocol
* Count number of scanned hosts, report it in debug mode
In scsi_rescan_new()
* Search for wwid in /sys/class/scsi_disk
* Use stricter search pattern
* Count number of found matches, report it in debug mode
Rename purestorage_unmap_disk() to remove_block_device()
In purestorage_resize_volume()
* Report that volume was resized after its new size is confirmed
* Use scsi_rescan_device() for iscsi
* Change "Info :: New size detected ..." to debug output
In map_volume()
* Use scsi_scan_new() for iscsi
In unmap_volume()
* Remove redundant block device check
* Change info messages to debug output
Include leading "3" into $purestorage_wwn_prefix
In purestorage_get_wwn()
* modify code to use updated $purestorage_wwn_prefix value
* add warning if volume is not found
In exec_command()
* die on error by default, update affected callers
* allow to invert success/failure with warning suppression (e.g. to support "fuser")
* update executables to full path inside of the function
* update affected callers
In wait_for()
* die on timeout instead of returning 0, update affected callers
In purestorage_unmap_disk()
* drop $class
* check that disk is a block device
In unmap_volume()
* improve error checking and logging
* add support for "fuser" check (but leave it commented out)
In scsi_rescan_device()
* remove 'multipath -r' call (there is a 'multipathd resize map' call)
* use multipathd for certain functions
* suppress output of exec_command() by default if $DEBUG value is less than 3
* introduce multipath_check() function
* eliminate purestorage_cleanup_diskmap()
Introduce wait_for() function
* to be used instead of waiting loops
* reduce default timeout and sleep delay
* do not log "Waiting for..." unless it actually waited
* show total time spent while waiting [not counting actual wait checks]
In purestorage_resize_volume()
* replace "multipath -r" call (unneeded reload of *all* multipath maps) with "multipathd resize map" call
* use wait_for() instead of waiting loop
In map_volume()
* remove unneeded "multipath -a" call
* use wait_for() instead of waiting loop
* call "multipathd add map" unless multipath_check() succeeds
In unmap_volume()
* use multipath_check()
* remove unneeded "multipath -w" call
* replace "multipath -f" with "multipathd remove map" call, die on error
* ActiveCluster is enabled by providing comma-separated cluster arrays parameters in "address" and "token"
* retry non-API errors on a second array
* connect/disconnect volumes to host on both arrays
* related code refactoring and improvements