* refactor: one task-response parser, and the dead code #154 names (part A)
Unifies the 8 byte-similar private ParseTask methods in BackupService,
ContainerService, NetworkService, NodeService, SnapshotService,
StorageService, TemplateService, and VmService into one shared
PveTaskResponse.Parse(json, node) utility, on the variant that stamps
Status = "running" for a bare-UPID response. BackupService, NodeService,
TemplateService, and VmService previously left Status null for that case;
their non--Wait task output now reports "running" like the other four
services already did.
Removes the duplicate ClusterConfigService.GetClusterStatus in favor of
ClusterService's; ClusterConfigService now holds a ClusterService built
from the same injected/default client, and WaitForQuorum and
Get-PveClusterStatus go through it.
Removes dead code named in issue #154 and its fold-in comments: the
never-called PveHttpClient/IPveHttpClient sync wrappers Put/Delete, the
never-thrown PveAuthenticationException, a #pragma around an
already-nullable field, the unreferenced TestHelper mock-handler helpers,
three hand-rolled version-warning blocks (now PveCmdletBase.WarnIfBelowVersion),
an unreachable catch(HttpRequestException) arm in WaitForStatusTransition,
dead ExitStatus-checking branches in ImportPveOvaCmdlet after WaitForTask
(which already throws on failure), and an unreachable int branch in
ApiValueHelper.IsExited.
Fixes the WaitForStatusTransition catch removal's premise: PveHttpClient
read the response body outside its HttpRequestException try block, so a
mid-body stream drop could still escape unwrapped. Moves the body read
inside the try so every HttpRequestException the client can throw becomes
a PveApiException, matching what the removed catch assumed.
Part of #154.
* Add service files: BackupService, ClusterConfigService, ContainerService, NetworkService
* Add service files: NodeService, SnapshotService, StorageService, TemplateService
* Add VmService and Utilities files
* Remove unused PveAuthenticationException (never thrown, caught, or tested)
* Add cmdlet files: GetPveClusterStatus, SDN subnets, PveCmdletBase, SendPveFile, ImportPveOva
* Add test files: BackupServiceTests, ClusterConfigServiceTests, NodeServiceTests
* Add remaining test files: TemplateServiceTests, VmServiceTests, TestHelper, ApiValueHelperTests, PveTaskResponseTests
* Add VmServiceTests
---------
Co-authored-by: goodolclint-claude[bot] <323206664+goodolclint-claude[bot]@users.noreply.github.com>
Every service method built and disposed its own PveHttpClient, and each
client owned a fresh HttpClientHandler, so every API call was a TCP connect
plus a TLS handshake and WaitForTask paid that 300 times over a ten-minute
wait.
PveServiceBase now owns the injected-or-fresh client lifetime behind one
Invoke helper; the 201 hand-written try/finally blocks across the 16
services collapse to calls on it, and the nested NodeService/VmService
instances receive the injected client. PveHttpClient takes its handler
from a process-wide PveHandlerCache keyed on (host, port,
skipCertificateCheck) and never disposes it, so the connection pool
outlives any one client. WaitForTask holds one client for the whole wait
and, when no pollInterval is supplied, backs off from 1 s toward a 10 s
cap, never sleeping past the deadline.
Co-authored-by: goodolclint-claude[bot] <323206664+goodolclint-claude[bot]@users.noreply.github.com>
D001-D021 become ADR 0001-0021 in docs/decisions/, one decision per file.
D017's PESTER_VERSION amendment was a second decision in one entry and becomes
ADR 0022. ADR 0023 records the migration and reverses the lane2-change-plan
ruling that deliberately kept DECISIONS.md until the CI lane work landed.
DECISIONS.md is reduced to a stub with a D-to-ADR redirect table, so the four
released CHANGELOG entries and older issue bodies that cite it degrade to a
redirect rather than a dead reference.
docs/review/ and docs/lane2-change-plan.md are deleted (ADR 0024). Of 91
findings, 83 were resolved and six of the seven still open were already GitHub
issues; F021 was the exception and is now #130.
CLAUDE.md's Key Conventions list gains the two rules it was missing and becomes
the checklist, with the ADRs carrying rationale.
Polls GET /cluster/status for the cluster entry with quorate = 1, bounded
by a timeout (60 s default) and tolerating PveApiException while pmxcfs
and corosync restart during cluster formation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Replace null-forgiving operator on Marshal.PtrToStringUni with
null-coalescing fallback (AddPveClusterMemberCmdlet.cs:64)
- GetNextId now throws InvalidOperationException instead of silently
returning 0 when API response cannot be parsed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract ParseLinks helper to PveCmdletBase for shared link parsing
with WriteWarning on malformed entries (was duplicated in 3 cmdlets)
- Fix GetClusterConfig to return data payload, not full API envelope
- Fix OutputType on GetPveClusterConfigCmdlet to JObject
- Fix link doc comments to use correct key format (link0..link7)
- Add null-safe Properties hashtable conversion in HA rule cmdlets
- Use case-insensitive Mode comparison in MovePveHaResourceCmdlet
- Remove unused using directives
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>