storage-api-stub-authoring
Skill35 starsChanged 7 months agoApache-2.0View on GitHub
Guides implementation of Storage Provider shims in-place under isvctl/configs/providers/my-isv/ — fill TODO blocks in scripts/storage/api.py and edit storage-provider-manifest.yaml. Does not copy to new provider dirs or scaffold full provider trees. Walks through each method with pointed questions and runs isolated sanity probes. Use when the user mentions storage shim, StorageApi, storage-provider-manifest, StorageProviderApiCheck, or storage provider stubs.
In this repository4 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/karpathy-guidelines.mdcCursor rule
- .cursor/rules/python-standards.mdcCursor rule
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. About 0 are common, 6 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 102
Ask permission before any discovery command: If granted, run probes from repo root.
- Very specific: line 140
Network locality: If the management API is only reachable in-cluster (VAST VMS pattern), note that isvctl deploy run may be required …
- Very specific: line 155
Do not: create providers/<customer>/ or copy these files elsewhere unless prompted by the user.
- Very specific: line 159
Read scripts/storage/api.py end-to-end — every method has a TODO block to replace
- Distinctive: line 160
Read AWS/VAST reference shims for patterns matching intake answers
- Very specific: line 161
Update config/overlays/storage-provider-manifest.yaml (v1alpha2): providers[].name, identity/provider, shim, capabilities — see …
- Very specific: line 162
Keep shim.module: ../../scripts/storage/api.py (relative to config/overlays/)
- Very specific: line 163
Keep DEMO_MODE until real backend calls land — enables smoke without credentials
- Distinctive: line 219
Follow method-walkthrough.md.
- Distinctive: line 248
Run before full suite. Order matters.
- Distinctive: line 272
Use patterns from the reference READMEs:
- Distinctive: line 302
Gate: Do not proceed to Phase 5 until 4a–4c pass (4d acceptable during scaffolding).
- Very specific: line 308
Run only when the user wants end-to-end StorageProviderApiCheck validation.
- Very specific: line 337
Only after Phase 5 passes.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Storage API Stub Authoring
Interactive workflow for implementing a provider's storage shim. Follow this skill end-to-end; do not skip intake or sanity gates.
Scope boundaries (read first)
Default workspace: isvctl/configs/providers/my-isv/
Implement by filling in the existing stubs — replace TODO blocks in
scripts/storage/api.py and update the sibling manifest. Do not cp or
cp -r my-isv to providers/<customer>/ unless the user explicitly requests
a separate handoff folder.
| In scope (my-isv) | Path |
| Required | scripts/storage/api.py — edit MyStorageApi TODO blocks in place |
| Required | config/overlays/storage-provider-manifest.yaml |
| Harness (exists) | config/storage.yaml — tweak in place if needed for tests |
| Optional | scripts/storage/README.md (document env vars when stub is done) |
AWS/VAST/weka paths under providers/aws/, providers/vast/, etc. are
read-only references — study them; do not copy their layout into new dirs.
Out of scope — do not create, copy, or edit unless the user explicitly asks:
- New provider directories (
providers/<customer>/) - Other
config/*.yamlorscripts/**trees in my-isv (if any exist) - Full-provider scaffold (
cp -r my-isv …)
Running my-isv/config/storage.yaml with --capability kubernetes is optional,
only when the user wants k8s-integrated runs.
Outcomes
By session end the user should have:
config/overlays/storage-provider-manifest.yamldeclaring the provider and pointing at the shimscripts/storage/.../api.pyimplementingStorageApi+build_api()- Documented env vars in
scripts/storage/README.md(when stub is complete) - Passing isolated probes (
probe_shim.py) before any fullisvctl test run config/storage.yaml'sstorage_manifeststep still pointing at the manifest (already declared)
Reference implementations (read before coding)
| Backend | Shim | Manifest | Config |
| AWS FSx Lustre | isvctl/configs/providers/aws/scripts/storage/fsx-lustre/api.py | aws/config/overlays/storage-provider-manifest.yaml | aws/config/storage.yaml |
| VAST NFS | isvctl/configs/providers/vast/scripts/storage/vast/api.py | vast/config/overlays/storage-provider-manifest.yaml | vast/config/storage.yaml |
| WEKA | isvctl/configs/providers/weka/scripts/storage/weka/api.py | weka/config/overlays/storage-provider-manifest.yaml | weka/config/storage.yaml |
| Authoring target (edit in place) | my-isv/scripts/storage/api.py | my-isv/config/overlays/storage-provider-manifest.yaml | my-isv/config/storage.yaml |
Contract: isvtest/src/isvtest/core/storage_provider/api.py (per-method
docstrings cover inputs/outputs, error conditions, and capability/qualifier semantics)
Check drivers:
isvtest/src/isvtest/validations/storage_provider.py(StorageProviderApiCheck)isvtest/src/isvtest/validations/storage_quota_enforcement.py(StorageDirectoryQuotaEnforcementCheck— live CRUD + write enforcement; needs K8s)
Manifest (schema v1alpha2):
- Schema:
isvctl/schemas/storage-provider-manifest.schema.json - Fully-populated example:
my-isv/config/overlays/storage-provider-manifest.example.yaml - Manifest → step adapter:
isvctl/configs/shared/storage/storage_manifest_to_steps.py(resolves the manifest path, loads no shim; thestorage_manifeststep instorage.yaml)
Session workflow
Copy this checklist and update as you go:
Progress:
- [ ] Phase 0: Intake + environment permission (discover what's there)
- [ ] Phase 1: Confirm my-isv files
- [ ] Phase 2: Generate manifest (discover + Q&A) + config wiring
- [ ] Phase 3: Implement StorageApi methods (one at a time)
- [ ] Phase 4: Isolated sanity probes
- [ ] Phase 5: Targeted StorageProviderApiCheck run
- [ ] Phase 6: Full suite guidance (optional)Phase 0: Intake and environment access
Ask permission before any discovery command. If granted, run probes from repo root. If denied, ask the user to paste command output.
Work through intake-questions.md first. Summarize answers in a short "Implementation profile" before writing code.
Environment discovery (when permitted)
Discovery is the first half of manifest generation: probe the cluster/API to propose field values, then confirm the rest by Q&A. The full discover-vs-ask mapping for every manifest field is in manifest-generation.md.
Kubernetes (adjust namespace/context as needed):
kubectl config current-context
kubectl get storageclass -o wide
kubectl get sc <sc-name> -o yaml # provisioner, parameters, mountOptions
kubectl get csidriver
kubectl get nodes --show-labels # -> node_selector for the CSI/filesystem checks
kubectl get pods -A | grep -i csi # driver health hint + which nodes run node pluginMap findings into the v1alpha2 manifest (which drives
StorageProviderApiCheck ONLY):
providers[].provider.*/identity.*(infer vendor/protocol/type from the driver; ask for version)providers[].capabilities.*(what the shim'sproperties()reports)providers[].shim.*(module path / configmap / credentials_secret)
The StorageClass names, NFS expectations, and node selectors are NOT in the
manifest: the CSI / filesystem checks (K8sCsiStorageTypesCheck,
K8sCsiDriverHealthCheck, K8sFile*, K8sNfsMountOptionsCheck, …) read them
from the suite/provider config or the K8S_CSI_* env vars (see
config-wiring.md).
Network locality: If the management API is only reachable in-cluster (VAST VMS pattern), note that isvctl deploy run may be required instead of laptop-side isvctl test run.
Phase 1: Work in my-isv
Open the existing files — they already contain TODO markers and DEMO_MODE:
isvctl/configs/providers/my-isv/
├── config/overlays/storage-provider-manifest.yaml # shim.module → ../../scripts/storage/api.py
├── config/storage.yaml # storage_manifest step already points at the manifest
└── scripts/storage/api.py # MyStorageApi — fill each TODO blockDo not create providers/<customer>/ or copy these files elsewhere unless prompted by the user.
Before coding:
- Read
scripts/storage/api.pyend-to-end — every method has aTODOblock to replace - Read AWS/VAST reference shims for patterns matching intake answers
- Update
config/overlays/storage-provider-manifest.yaml(v1alpha2):providers[].name,identity/provider,shim,capabilities— see manifest-generation.md - Keep
shim.module: ../../scripts/storage/api.py(relative toconfig/overlays/) - Keep
DEMO_MODEuntil real backend calls land — enables smoke without credentials
Rename MyStorageApi / properties() identity fields to match the backend; keep
build_api() at module level.
Phase 2: Manifest generation and config wiring
Generate config/overlays/storage-provider-manifest.yaml (schema v1alpha2) using the
discover-then-ask workflow in
manifest-generation.md: probe the
environment to propose field values, ask the customer for what you can't
observe, and omit (don't guess) anything still unknown so the dependent check
skips cleanly. config/storage.yaml already declares the storage_manifest step that
feeds it to the checks — see config-wiring.md.
Two files ship beside the template — use them as you fill the blank one:
config/overlays/storage-provider-manifest.yaml— blank template to edit in placeconfig/overlays/storage-provider-manifest.example.yaml— fully-populated v1alpha2 reference (every field)
The manifest is a contract, not docs. For providers with a shim: block,
StorageProviderApiCheck cross-checks declared identity/capabilities against
the running shim and fails on mismatch (manifest-consistency[<name>]). Only
declare what the shim actually reports; omit a field to leave it unchecked.
Validate the draft without a backend (parses the manifest, loads no shim):
STORAGE_PROVIDER_MANIFEST=isvctl/configs/providers/my-isv/config/overlays/storage-provider-manifest.yaml \
uv run python isvctl/configs/shared/storage/storage_manifest_to_steps.py | uv run python -m json.toolCritical couplings:
| Artifact | Purpose |
shim.module | Relative to manifest parent; must resolve to api.py with build_api() |
storage_manifest step in provider YAML | STORAGE_PROVIDER_MANIFEST resolves to the manifest_path passed to StorageProviderApiCheck (on-disk now; ConfigMap mount path in prod) |
Env vars in shim __init__ | Runtime config — manifest attributes are informational only |
K8S_CSI_* env vars / config overrides | StorageClass names for the CSI/filesystem checks — set in config/env, NOT the manifest |
Provider wiring pattern: the suite's storage_provider_api group is bound to
the storage_manifest step — see config-wiring.md.
ConfigMap handoff (document for customer, do not implement operator):
- Manifest → ConfigMap
storage-provider-manifest, keymanifest.yaml - Shim
api.py→ per-provider ConfigMap referenced byshim.configmap - Credentials → per-provider Secret; env vars at runtime
Phase 3: Implement methods (one at a time)
Follow method-walkthrough.md. Implement and probe each method before moving on. Ask the pointed questions listed there.
Decision tree: volume lifecycle
Does a CSI driver dynamically provision PVCs on this cluster?
├─ YES (managed K8s — AWS FSx, VAST, WEKA pattern)
│ → create_volume / delete_volume raise NotSupportedError
│ → list_volumes MUST return existing CSI-provisioned volumes (count ≥ 1 for N-020 pass)
│ → Populate Volume.csi (driver + volume_handle) when discoverable
└─ NO (bare-metal / API-managed storage)
→ Implement create_volume + delete_volume
→ Tag volumes with isvtest-run-id for orphan sweepProviderProperties
Declare capabilities honestly in storage-provider-manifest.yaml, and implement
only the corresponding methods in scripts/storage/api.py. new_implementation()
detects which surfaces are backed and advertises the merged capability set.
Directory-quota shims should also exercise
StorageDirectoryQuotaEnforcementCheck under a K8s config (optional
pvc_name / pod_name reuse for faster iteration — see provider READMEs).
Phase 4: Isolated sanity probes
Run before full suite. Order matters.
4a. Manifest loads
uv run python -c "
from isvtest.core.storage import load_provider_registry
ps = load_provider_registry({'manifest_path': 'isvctl/configs/providers/my-isv/config/overlays/storage-provider-manifest.yaml'})
print([p.name for p in ps if p.has_shim])
"4b. Shim probe script
uv run python .cursor/skills/storage-api-stub-authoring/scripts/probe_shim.py \
--manifest isvctl/configs/providers/my-isv/config/overlays/storage-provider-manifest.yamlExpect: health_check ok, get_tenant_quota with hard_limit_bytes > 0, and either
create_volume path or list_volumes returning ≥1 volume (CSI fallback).
4c. Backend-specific CLI probes
Use patterns from the reference READMEs:
- AWS:
aws sts get-caller-identity,aws fsx describe-file-systems,aws service-quotas get-service-quota - VAST:
curl -H "Authorization: Api-Token $VAST_TOKEN" "https://$VAST_ENDPOINT/api/quotas/" - Generic: whatever authenticated GET the shim's
health_checkuses
4d. Demo mode smoke (no credentials, optional)
Uses the existing my-isv/config/storage.yaml harness:
ISVCTL_DEMO_MODE=1 \
uv run isvctl test run -f isvctl/configs/providers/my-isv/config/storage.yaml4e. Contract / validation unit tests
# Shim contract package (ABC, loader, mock)
uv run pytest isvtest/src/isvtest/core/storage_provider/tests/
# StorageProviderApiCheck behavior (framework tests)
uv run pytest isvtest/tests/test_storage_provider.py
# Provider-specific hermetic shim tests, when added:
uv run pytest isvtest/tests/test_aws_fsx_lustre_shim.py
uv run pytest isvtest/tests/test_weka_shim.py
uv run pytest isvtest/tests/test_storage_quota_enforcement.pyGate: Do not proceed to Phase 5 until 4a–4c pass (4d acceptable during scaffolding).
Phase 5: Targeted acceptance check (optional)
Run only when the user wants end-to-end StorageProviderApiCheck validation.
Requires a storage.yaml with a storage_manifest step.
uv run isvctl test run -f isvctl/configs/providers/my-isv/config/storage.yamlFor K8s-integrated runs, run the same storage.yaml with --capability kubernetes
— do not create a new config or a full provider tree.
Expected CSI fallback (not a failure):
volume-provisioning[<name>] SKIPPED: create_volume not implemented; observed N CSI-provisioned volume(s)Common failures → fixes:
| Symptom | Fix |
AuthenticationError on health_check | Fix creds / network / IAM |
hard_limit_bytes=0 | Wrong quota source or empty tenant |
observed 0 ... via list_volumes | Create a PVC against the StorageClass first |
| Manifest not found | Run from repo root; fix manifest_path |
Phase 6: Full suite (optional)
Only after Phase 5 passes. Run storage.yaml (which imports only
isvctl/configs/suites/storage.yaml, never alongside suites/k8s.yaml) with
--capability kubernetes, and align:
- StorageClass names via the
K8S_CSI_*env vars (K8S_CSI_BLOCK_SC,K8S_CSI_SHARED_FS_SC,K8S_CSI_NFS_SC) or literal overrides in your config — these are NOT in the manifest k8s_storageCSI checks beyond the shim:K8sCsiStorageTypesCheck,K8sCsiStorageQuotaApiCheck,K8sCsiProvisioningModesCheck,K8sCsiConcurrentPvcCheck,K8sCsiPvcExpandCheck,K8sCsiDriverHealthCheckk8s_filesystemchecks (K8sFileLockingCheck,K8sCrossNodeWriteVisibilityCheck, …) andnode_selector(literal dict) when CSI requires labeled nodes
uv run isvctl test run -f isvctl/configs/providers/my-isv/config/<k8s-or-storage-config>.yamlAgent behavior rules
- Edit my-isv in place — fill
scripts/storage/api.pyTODO blocks; nevercp -r my-isvto a new provider dir unless the user explicitly asks for handoff. - One method at a time — implement
properties+__init__, thenhealth_check, thenget_tenant_quota, then volume methods. - Ask before assuming — especially CSI vs API provisioning, tenant model, quota semantics.
- Match reference style — env-driven config, tight IAM/API surface,
NotSupportedErrorfor CSI-owned lifecycle. - Do not add setup scripts — this skill does not author provider orchestration steps.
- Document env vars in
scripts/storage/README.mdwhen the stub is done (in-scope). - Test harness on request — run
storage.yamlonly when the user wants to run checks; itsstorage_manifeststep is already wired.
Additional resources
- manifest-generation.md — discover-then-ask, field-by-field manifest authoring (v1alpha2)
- intake-questions.md — upfront questionnaire
- method-walkthrough.md — per-method questions and acceptance criteria
- config-wiring.md — manifest, overrides, CSI, ConfigMap
- AWS stub implementation
- VAST stub implementation
- WEKA stub implementation
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

