feat(storage): add -Target and -Portal parameters to New-PveStorage for iSCSI

New-PveStorage now supports configuring iSCSI storage backends natively:
  -Target: iSCSI target IQN (e.g. iqn.2024-01.com.example:storage)
  -Portal: iSCSI portal address (host:port, defaults to server:3260)

Also refactored ProcessRecord to use AddIfNotEmpty helper, reducing
cognitive complexity.

Added unit tests for all iSCSI/NFS parameter metadata and a new
SharedStorage.Tests.ps1 integration test file that tests NFS and iSCSI
storage create/verify/status/delete lifecycle against the Docker-based
storage containers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Clint Branham
2026-03-24 14:43:33 -05:00
parent ab768e114a
commit 064cc372cf
3 changed files with 246 additions and 10 deletions
@@ -63,6 +63,14 @@ namespace PSProxmoxVE.Cmdlets.Storage
[Parameter(Mandatory = false, HelpMessage = "Ceph monitor host list.")]
public string? MonHost { get; set; }
/// <summary>iSCSI target IQN (for "iscsi" type).</summary>
[Parameter(Mandatory = false, HelpMessage = "iSCSI target IQN (e.g. iqn.2024-01.com.example:storage).")]
public string? Target { get; set; }
/// <summary>iSCSI portal address (for "iscsi" type). Defaults to server:3260 if not specified.</summary>
[Parameter(Mandatory = false, HelpMessage = "iSCSI portal address (host:port).")]
public string? Portal { get; set; }
/// <summary>Whether this storage is shared across cluster nodes.</summary>
[Parameter(Mandatory = false, HelpMessage = "Storage is shared across cluster nodes.")]
public SwitchParameter Shared { get; set; }
@@ -75,6 +83,12 @@ namespace PSProxmoxVE.Cmdlets.Storage
[Parameter(Mandatory = false, HelpMessage = "Limit access to these nodes (comma-separated).")]
public string? Nodes { get; set; }
private static void AddIfNotEmpty(Dictionary<string, string> data, string key, string? value)
{
if (!string.IsNullOrEmpty(value))
data[key] = value!;
}
protected override void ProcessRecord()
{
if (!ShouldProcess(Storage, "Create PVE Storage"))
@@ -98,16 +112,17 @@ namespace PSProxmoxVE.Cmdlets.Storage
["type"] = Type
};
if (!string.IsNullOrEmpty(Content)) data["content"] = Content!;
if (!string.IsNullOrEmpty(Path)) data["path"] = Path!;
if (!string.IsNullOrEmpty(Server)) data["server"] = Server!;
if (!string.IsNullOrEmpty(Export)) data["export"] = Export!;
if (!string.IsNullOrEmpty(VgName)) data["vgname"] = VgName!;
if (!string.IsNullOrEmpty(ThinPool)) data["thinpool"] = ThinPool!;
if (!string.IsNullOrEmpty(Pool)) data["pool"] = Pool!;
if (!string.IsNullOrEmpty(CephPool)) data["pool"] = CephPool!;
if (!string.IsNullOrEmpty(MonHost)) data["monhost"] = MonHost!;
if (!string.IsNullOrEmpty(Nodes)) data["nodes"] = Nodes!;
AddIfNotEmpty(data, "content", Content);
AddIfNotEmpty(data, "path", Path);
AddIfNotEmpty(data, "server", Server);
AddIfNotEmpty(data, "export", Export);
AddIfNotEmpty(data, "vgname", VgName);
AddIfNotEmpty(data, "thinpool", ThinPool);
AddIfNotEmpty(data, "pool", Pool ?? CephPool);
AddIfNotEmpty(data, "monhost", MonHost);
AddIfNotEmpty(data, "target", Target);
AddIfNotEmpty(data, "portal", Portal);
AddIfNotEmpty(data, "nodes", Nodes);
if (Shared.IsPresent) data["shared"] = "1";
if (Disable.IsPresent) data["disable"] = "1";