fix(presets): support PUT in Invoke-PfbApiRequest and fold Set-PfbPresetWorkload onto it - #78
Merged
juemerson-at-purestorage merged 2 commits intoAug 2, 2026
Conversation
Two PUT endpoints exist in the FlashBlade REST API (PUT /presets/workload and
PUT /workloads/tags/batch). Neither could be expressed through the shared
request path, so both cmdlets hand-rolled their own Invoke-RestMethod call and
in doing so skipped capability gating, error normalisation, and Bearer-token
auth. This adds the verb; folding the cmdlets back on follows separately.
Both edits are additive and no existing caller changes behaviour:
- 'PUT' joins the -Method ValidateSet.
- The body-serialisation guard gains PUT. It stays a whitelist of verbs that
may carry a body rather than becoming a "not GET" test, so a future verb
has to opt in deliberately instead of inheriting serialisation.
Nothing else in the function branches on $Method -- the only other site is the
pass-through into $restParams, and pagination keys off -AutoPaginate plus
continuation_token, never the verb. Assert-PfbApiCapability takes -Method as an
unconstrained [string] and Data/PfbCapabilityMap.json already carries both PUT
keys, so neither needed a change.
Tests cover the verb reaching Invoke-RestMethod with a serialised body, a PUT
without a body sending no Body key, and -- as a guard against widening the body
guard too far -- GET and DELETE still dropping a body when one is supplied.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The cmdlet hand-rolled its own Invoke-RestMethod call because the shared path
could not express PUT. That is no longer true, so the bypass goes away and the
cmdlet picks up everything Invoke-PfbApiRequest layers on.
Three user-visible consequences, none of them silent:
- Capability gating now runs. Set-PfbPresetWorkload and Set-PfbWorkloadTag
were the only two write cmdlets in the module exempt from it. A call
against an array below REST 2.23 now throws locally instead of being sent
and rejected on the wire.
- Errors now come from ConvertTo-PfbApiError rather than surfacing a raw
Invoke-RestMethod exception, matching every other write cmdlet.
- OAuth2/Certificate sessions work. The hand-rolled block set x-auth-token
unconditionally and never consulted $Array.BearerToken, so the cmdlet was
broken for certificate-authenticated connections. This was not mentioned in
the comment it carried and is fixed here as a side effect.
Body serialisation moves to the shared path's -Depth 10, down from the local
-Depth 15. The resolved PUT /presets/workload request schema nests 8 levels, so
nothing truncates.
Assert-PfbConnection and the ShouldProcess gate are unchanged; ShouldProcess
still wraps the call rather than the parameter construction.
Adds Tests/Set-PfbPresetWorkload.Tests.ps1 -- the cmdlet had no tests. Beyond
verb/endpoint/body/query coverage it asserts that no direct Invoke-RestMethod
call escapes the cmdlet, which is the regression that would undo this change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 2, 2026
Open
juemerson-at-purestorage
added a commit
that referenced
this pull request
Aug 3, 2026
…m order (#86) * fix(tools): emit report records in canonical order, not filesystem order Get-PfbCmdletParameterInventory and Get-PfbModuleCalledEndpoints both walked Public//Private/ with an unsorted recursive Get-ChildItem and let that walk become the emit order of their records. Regenerating Reports/ on a Linux CI runner instead of a Windows workstation therefore produced a 10,218-line diff across PfbFieldCmdletMap.json/.md and PfbApiDriftReport.json/.md with zero semantic change -- all 2015 entries moved, not one changed content, and the two files were even identical in byte length. That is what makes the update-api-capability-map auto-PR unreviewable. Sorted at emit rather than only on the file list: FullName carries platform-specific separators, so sorting the walk alone is the fragile fix. The walk is sorted too, but only as belt-and-braces for intermediate debugging output. Every sort pins -Culture '' (invariant) so the runner locale cannot reintroduce the divergence. Also replaces Select-Object -Unique with Sort-Object -Unique at the intra-row cmdlet list in Get-PfbParameterCoverageGaps (-Unique preserves input order and does not sort -- the observed `Get-PfbArray, Test-PfbConnection` flip), and sorts the Group-Object groups themselves, whose order is first-appearance in the input and so was also file-walk-derived. The regression tests deliberately do not regenerate twice on one machine -- that is the assertion Tests/Build-PfbApiDriftReport.Tests.ps1 already makes, and enumeration order is stable within a filesystem, so it can never fail. Instead two fixture trees hold the same cmdlets with the cmdlet-to-filename mapping swapped, which reproduces the divergence on any single platform and needs no tools/specs (so it will not silently skip in a fresh clone -- see #63). Refs #85 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(reports): regenerate under the canonical emit order Do NOT review this line by line. Two of the four files are a pure re-sort; the review that matters is the canonical comparison, reproduced below. Reports/PfbFieldCmdletMap.json and .md -- pure re-sort, zero content change: order-insensitive-equal vs committed: true entries 2015 -> 2015 multiset-equal 2015/2015 repositioned attributesOnly 68 -> 68 multiset-equal 65/68 repositioned typedUnresolved 39 -> 39 multiset-equal 35/39 repositioned markdown: identical line multiset, 161 lines both sides Generating the same artifact with HEAD~1's tools/lib and with this branch, from identical inputs, gives byte-length-identical files (586,461 both) that are order-insensitive-equal -- so the sort provably reorders and never rewrites. Reports/PfbApiDriftReport.json came out raw-identical between those two runs: on NTFS the unsorted walk already happened to yield the canonical order, which is precisely why this defect was invisible from a Windows workstation. Reports/PfbApiDriftReport.json and .md -- a real, expected content refresh, NOT part of the re-sort. The committed copies predate PRs #78/#81: uncoveredEndpoints 98 -> 96 PUT /presets/workload, PUT /workloads/tags/batch parameterGaps 436 -> 438 the same two, now as gap rows systemicGaps 252 -> 252 context_names 269 -> 270; 13 body-property names +1 each, all from Set-PfbPresetWorkload Those PRs routed Set-PfbPresetWorkload/Set-PfbWorkloadTag through Invoke-PfbApiRequest, which is the only thing the AST resolver can see -- so the endpoints leave the uncovered list and Set-PfbPresetWorkload immediately reappears carrying 14 missing body properties. "Uncovered -> covered" here means visible to the scanner, not finished; see #85 and the #45/#44 caveat. Per #85, the two artifacts that must NOT move were regenerated and hashed to confirm they did not: Data/PfbCapabilityMap.json (632 endpoints, 29 versions, -MaxVersion 2.28) and Reports/PfbValueEnumMap.json are both byte-identical to their committed copies. Tests/Build-PfbApiDriftReport.Tests.ps1's "no serialization-only divergence" invariant was already failing on main with 19 differences, unchanged by the sort, and passes again now the report is current. Refs #85 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
juemerson-at-purestorage
deleted the
fix/invoke-put-support-preset-workload
branch
August 9, 2026 18:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #76.
Set-PfbPresetWorkloadhand-rolled its ownInvoke-RestMethodcall, with a commentexplaining that the shared request path could not express PUT. That was true when the
cmdlet was written. It is no longer true after the first commit here, so the bypass goes
away.
What changed
Invoke-PfbApiRequestaccepts PUT (cedf31a).PUTjoins theValidateSet, and thebody-serialisation guard stays an explicit whitelist (
POST/PATCH/PUT) rather thanbecoming a "not GET" test — a future verb has to opt into carrying a body deliberately.
Set-PfbPresetWorkloadroutes through it (b56165c). Twelve lines of hand-rolledrequest construction become one call.
Assert-PfbConnectionand theShouldProcessgateare unchanged.
Three consequences, none of them silent:
Set-PfbWorkloadTagwere the only twowrite cmdlets in the module exempt from it. A call against an array below REST 2.23 now
throws locally instead of going out on the wire to be rejected.
ConvertTo-PfbApiError, matching every other writecmdlet, instead of surfacing a raw
Invoke-RestMethodexception.x-auth-tokenunconditionally and never consulted
$Array.BearerToken, so the cmdlet was broken forbearer-authenticated connections. The comment it carried did not mention this; it is
fixed here as a side effect of the fold.
Body serialisation moves to the shared path's
-Depth 10, down from the local-Depth 15.The resolved
PUT /presets/workloadrequest schema nests 8 levels, so nothing truncates.Please read this part before merging
This cmdlet does not work today, and it does not work after this PR either. That is not
a regression introduced here — it has never worked. I found this while live-testing, and it
is worth recording because the issue as filed implies the fold makes the cmdlet correct.
Every preset write, and every name-scoped preset read, requires
context_names=<fleet>.No cmdlet in
Public/Presets/has ever sent it. Tested against FB-A (Purity//FB 4.8.2,REST 2.26) as a dynamic-authorization-model admin, against a preset that genuinely existed:
Get-PfbPresetWorkload(unfiltered)Get-PfbPresetWorkload -NamePreset does not exist.Set-PfbPresetWorkload -NamePreset does not exist.New-PfbPresetWorkloadCreating a preset in the array context is not supported.Remove-PfbPresetWorkload -NamePreset does not exist.Update-PfbPresetWorkloadFive of six preset operations are non-functional. What this PR changes is that
Set-PfbPresetWorkloadis now fixable in one place: it was the last preset cmdlet routingaround the shared request path, so whatever adds
context_namescentrally will reach itwithout a special case. That is the value here — the rewiring, not a working cmdlet.
One finding for the context work, from the same testing:
/presets/workloadrejects amember array as context (
context_names=<member>→code 13 Invalid context) and acceptsonly the fleet name, on every verb. The shared
Context_namescomponent description("an array in the same fleet or the name of the fleet itself") is wrong for this endpoint.
Verification
Tests/Set-PfbPresetWorkload.Tests.ps1is new — the cmdlet had no tests at all. Beyondverb/endpoint/body/query coverage it asserts
Invoke-RestMethod -Times 0, which is theregression that would quietly undo this change.
Tests/Invoke-PfbApiRequest.Tests.ps1gains PUT coverage: body serialisation, PUT with nobody, GET/DELETE still sending no body, and an out-of-set verb failing parameter binding.
Windows PowerShell 5.1 (Pester 6.0.1, CI's pin).
context, plus the matrix above. Lab left clean.
No version or CHANGELOG changes.
🤖 Generated with Claude Code