Skip to content

OSAC-2876: Storage Control Plane design - #151

Merged
openshift-merge-bot[bot] merged 12 commits into
osac-project:mainfrom
akshaynadkarni:osac-2876-storage-control-plane-design
Jul 28, 2026
Merged

openshift-merge-bot[bot] merged 12 commits into
osac-project:mainfrom
akshaynadkarni:osac-2876-storage-control-plane-design

Conversation

@akshaynadkarni

@akshaynadkarni akshaynadkarni commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Design: Storage Control Plane

Jira: OSAC-2872
PRD: prd.md (merged in PR #134)

Summary

Introduces a vendor-agnostic storage layer for OSAC CaaS tenant clusters. A single CSI driver (csi.osac.openshift.io) presents opaque storage tiers to tenants. The fulfillment-service handles tier resolution, policy enforcement, and volume inventory via a private Volume API. The osac-operator reconciles Volume CRs on the hub cluster, calling vendor CSI controllers to create and delete volumes on storage arrays. This follows the established OSAC resource lifecycle pattern (same as ComputeInstance and ClusterOrder).

Key design decisions

  • Volume CR + dual-controller pattern: fulfillment-service creates Volume CR on the hub, osac-operator reconciles it (calls vendor CSI), feedback controller syncs status back
  • Vendor controller routing: in-cluster DNS (vast.osac-csi-backend.svc.cluster.local), operator and vendor controller on the same hub
  • Credentials: operator derives per-tenant creds from existing hub Secret (vast-tenant-config-{tenant}), credentials never leave the hub
  • PVC/PV tracking: cross-cluster GET + requeue to confirm PVC binding, annotations on PVC/PV for OpenShift UI filtering
  • Cluster teardown: finalizer on ClusterOrder, uses PV reclaim policy to decide delete vs retain
  • Cross-cluster auth: tenant user credentials for first release

Requesting Review On

  • Cross-cluster PVC/PV verification: the operator uses cross-cluster GET + requeue (not a persistent watch) to confirm PVC binding on the tenant cluster. See Volume Controller section.
  • Volume-cleanup finalizer on ClusterOrder: blocks cluster deletion until volumes are processed. Coexists with the existing cluster-storage finalizer. See Cluster teardown cleanup section.
  • Vendor controller namespace: osac-csi-backend with service name matching the provider (e.g., vast).

How to Review

  • Comment inline on specific sections
  • Approve when the design accurately reflects a viable implementation approach

Assisted-by: Cursor/Claude

Summary by CodeRabbit

  • Documentation
    • Added a new design document for OSAC’s vendor-agnostic tenant block storage “storage-control-plane” in OSAC CaaS clusters.
    • Defines the end-to-end volume lifecycle, including orchestration, reconciliation flow, and idempotent retry behavior.
    • Details CSI driver expectations (including polling/retry semantics), StorageClass conventions, and security/authz boundaries.
    • Documents required volume API contracts and lifecycle states (conditions/phases/finalizers), plus observability and failure/recovery guidance.

Design for the vendor-agnostic storage layer covering the OSAC CSI
meta-driver, fulfillment-service Volume API and storage logic layer,
Helm chart packaging, and automated cluster storage deployment via AAP.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@openshift-ci-robot

openshift-ci-robot commented Jul 23, 2026 •

Copy link
Copy Markdown

@akshaynadkarni: This pull request references OSAC-2876 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Design: Storage Control Plane

Jira: OSAC-2872
PRD: prd.md (merged in PR #134)

Summary

Introduces a vendor-agnostic storage layer for OSAC CaaS tenant clusters. A single CSI driver (csi.osac.openshift.io) presents opaque storage tiers to tenants, while a storage logic layer inside the fulfillment-service handles tier resolution, policy enforcement, credential management, and volume inventory. The design covers five core capabilities: CSI driver, storage internal API, volume inventory with private Volume API, Helm chart packaging, and automated cluster storage deployment via AAP.

Requesting Review On

  • Open Question 1: Cross-cluster authentication mechanism. The design recommends per-cluster service account tokens but this has not been formally decided. See Open Questions section.
  • Open Question 2: VAST CSI controller deployment model. Shared vs per-tenant Deployment on the hub cluster.
  • Open Question 3: StorageClass naming convention. Transition from vast-{protocol}-{tenant}-{tier} to OSAC-prefixed names.
  • StorageInternal as internal packages vs gRPC service. The design internalizes tier resolution, policy, and credential logic as Go packages rather than a separate StorageInternal gRPC service. Rationale in API Extensions and Alternatives sections.

How to Review

  • Comment inline on specific sections
  • Approve when the design accurately reflects a viable implementation approach

Assisted-by: Cursor/Claude

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The design document specifies a vendor-agnostic storage control plane for OSAC tenant clusters, covering Volume APIs, CSI integration, reconciliation workflows, security, deployment, observability, testing, and rollout procedures.

Changes

Storage control plane

Layer / File(s) Summary
Control-plane architecture and workflows
enhancements/OSAC-2872-storage-control-plane/design.md
Defines component ownership, storage lifecycle workflows, mount routing, and failure handling.
Volume API and CSI integration
enhancements/OSAC-2872-storage-control-plane/design.md
Specifies private gRPC contracts, fulfillment reconciliation, the Volume CRD lifecycle, CSI behavior, Helm resources, installer wiring, and AAP deployment changes.
Security and observability
enhancements/OSAC-2872-storage-control-plane/design.md
Documents authentication, credential isolation, tenant enforcement, validation, metrics, events, logging, and mitigations.
Validation and rollout requirements
enhancements/OSAC-2872-storage-control-plane/design.md
Defines alternatives, open questions, testing, graduation criteria, upgrade and version-skew handling, support procedures, and repository requirements.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CSI as OSAC CSI driver
  participant API as Fulfillment-service Volume API
  participant Operator as osac-operator
  participant Vendor as Vendor CSI controller
  CSI->>API: CreateVolume request
  API->>Operator: Create hub Volume CR
  Operator->>Vendor: Provision vendor volume
  Vendor-->>Operator: Update Volume status
  Operator->>API: Signal volume state
  API-->>CSI: Return AVAILABLE volume
Loading

Suggested reviewers: avishayt, wgordon17, zszabo-rh

🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the PR’s main change: a storage control plane design document.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No-Hardcoded-Secrets ✅ Passed No hardcoded secrets found; the design doc only references credential concepts/placeholders, with no actual keys, tokens, passwords, base64 blobs, or embedded-auth URLs.
No-Weak-Crypto ✅ Passed Only the design doc changed; it contains no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, no custom crypto, and no secret/token comparisons.
No-Injection-Vectors ✅ Passed Only changed file is a Markdown design doc; no eval/exec, shell=True, yaml.load, os.system, pickle.loads, or dangerouslySetInnerHTML patterns were present.
Container-Privileges ✅ Passed Only design.md changed; no K8s/container manifests or privilege settings (privileged, hostPID/Network/IPC, SYS_ADMIN, allowPrivilegeEscalation) were found.
No-Sensitive-Data-In-Logs ✅ Passed No log statements or examples expose passwords, tokens, PII, session IDs, or internal hostnames; logging is described only generically.
Ai-Attribution ✅ Passed AI use is disclosed with an Assisted-by: Cursor/Claude trailer in the commit message; no AI-related Co-Authored-By found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 8/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptionally detailed implementation. Full proto schemas with field types for Volume, VolumeSpec, VolumeStatus, VolumeState enum, and the Volumes gRPC service with REST transcoding annotations. CreateVolume handler logic is a 6-step algorithm with specific validation rules, error codes (PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE), and state transitions. All lifecycle operations covered (Create, Get, List, Update, Delete, Signal). Eight specific failure modes documented with recovery paths and us
Testability 2/2 Test plan is thorough at all three levels with specific scenarios. Unit tests enumerate what is tested for both fulfillment-service (5 areas: Volume API server state transitions, tier resolution, policy engine, credential manager, migration) and osac-csi-driver (4 areas: controller CreateVolume/DeleteVolume flows, node routing, fulfillment client). Integration tests specify tenant isolation verification and CSI sanity test suite. E2E tests list 5 concrete user-observable scenarios including erro
Scope 2/2 Clear boundaries with tight focus on CaaS PVC provisioning via private Volume API. PRD referenced in frontmatter and summary. Five specific non-goals with Jira references (public API deferred to OSAC-984, quota lifecycle, VMaaS, CSI certification, multi-vendor). Three real alternatives with detailed pros/cons/rationale. Most cross-cutting dimensions addressed: storage (core feature), tenant onboarding (AAP roles), provisioning (CSI deployment), installation (Helm umbrella chart), E2E testing (te
Architecture 2/2 Follows all major OSAC patterns. Volume proto uses standard object shape (id, Metadata, Spec, Status) with clean spec/status ownership separation. Cross-repo dependencies are clearly identified across four repositories with a table explaining what each owns. Integration with existing StorageBackend/StorageTier, StorageReconciler, and AAP playbooks is well-described. Tenant isolation enforced via JWT claims and GenericDAO filtering. StorageClasses carry osac.openshift.io/tenant labels. Minor note

Verdict: A thorough, well-structured design document (635 lines) that provides deep technical detail across all dimensions — full proto schemas, step-by-step handler logic, comprehensive failure handling, real alternatives, and specific test scenarios at every level.

Feedback: Two minor improvements would strengthen this already strong design: (1) Add a brief documentation dimension note — even if deferred, state what docs are needed (architecture update for storage control plane, API reference for private Volume API, admin guide for CSI driver deployment). (2) Define concrete graduation criteria instead of deferring — e.g., 'Dev Preview: all CRUD operations pass e2e with VAST backend, error paths tested; Tech Preview: multi-tenant isolation verified, no regressions in existing storage conditions.' The access_mode field in VolumeSpec should ideally be an enum (AccessMode) rather than a string, per OSAC API conventions.

Critical (0)

None.

Important (2)

  1. Graduation criteria are deferred ('will be defined when targeting a release') rather than specifying measurable conditions for each stage. Even a rough set of criteria (e.g., 'Dev Preview: CRUD lifecycle passes e2e; Tech Preview: multi-tenant isolation verified under load') would strengthen the design's testability posture.
  2. Documentation cross-cutting dimension from osac-dimensions.md is not addressed or explicitly deferred. The design should state what documentation changes are needed (architecture docs, admin guide for CSI driver deployment, API reference) or explicitly defer them.

Suggestions (3)

  1. VolumeSpec.access_mode is a string — consider defining an AccessMode enum (ACCESS_MODE_READ_WRITE_ONCE, ACCESS_MODE_READ_ONLY_MANY, etc.) for type safety and proto validation, consistent with OSAC's enum convention for fixed value sets.
  2. Goals are implementation-focused ('Reuse existing GenericServer', 'Package as Helm chart') rather than user/operator-visible outcomes. Consider reframing as outcomes: 'Tenants can provision persistent volumes via opaque storage tiers without vendor exposure' and 'Cloud Infrastructure Admins can manage storage backends and tiers centrally.'
  3. The design uses a VolumeState phase enum rather than conditions. While reasonable for a DB record (not a CRD), a brief note acknowledging this trade-off against the OSAC convention of preferring conditions for new resources would preempt reviewer questions.

Review cost

Model: claude-opus-4-6
Cost: $0.6583
Tokens: 6 in / 5.4k out
Cache: 170.4k read
Active time: 2m 2s
API calls: 0

@github-actions github-actions Bot added the rfe-creator-auto-reviewed EP was reviewed by AI label Jul 23, 2026
@akshaynadkarni

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@enhancements/OSAC-2872-storage-control-plane/design.md`:
- Line 170: Remove the trailing whitespace from the PVC with unconfigured
StorageClass line in the design document, preserving its wording and formatting
otherwise.
- Around line 156-166: Update the design to require durable orphan cleanup
before GA: define ownership metadata for volumes, add cleanup during
cluster-termination/teardown workflows, and specify periodic reconciliation that
safely detects and removes vendor volumes whose inventory remains AVAILABLE or
CREATING when CSI DeleteVolume was skipped. Apply the same requirement to the
referenced deletion, teardown, and reconciliation sections.
- Around line 389-404: Update the deployment artifact configuration in the
driver and vendor image sections to replace every latest image tag with the
tested immutable image digest. Also update the associated Helm chart dependency
constraint from >=0.0.0 to an exact or bounded compatible version, preserving
the documented version-skew and rollback strategy.
- Around line 337-340: Remove the design that returns reusable VAST
username/password credentials through the CreateVolume response or any
tenant-cluster-facing Volume API. Update CredentialManager and the CSI
interaction so vendor authentication remains hub-side, or replace it with a
brokered short-lived mechanism that never exposes reusable vendor secrets to
tenant infrastructure; ensure the isolation claim remains accurate.
- Around line 174-175: Update the vendor provisioning flow described for Volume
API CreateVolume retries so VAST volume creation is idempotent even when the
controller crashes before UpdateVolume. Persist and reuse a deterministic vendor
request identity, or reconcile existing vendor state before issuing a new
creation request, ensuring retries cannot create duplicate vendor volumes when
the inventory record lacks a vendor ID.
- Around line 6-11: Align the PR/commit title with the canonical Jira identifier
OSAC-2872 referenced by the design metadata and PRD. If the work is actually for
OSAC-2876, update the linked issue references in the design and PRD consistently
instead.
- Line 27: The Volume API flow must explicitly treat provisioning’s CreateVolume
and UpdateVolume calls, and deprovisioning’s DeleteVolume and UpdateVolume
calls, as separate gRPC operations rather than one call per volume operation.
Update the corresponding provisioning and deprovisioning sections to define
retry and timeout behavior for each call, including the second UpdateVolume
call, and ensure monitoring and alerting cover both calls consistently.
- Around line 356-367: The vendor CSI proxy flow must require authenticated,
identity-validated transport rather than unrestricted configurable gRPC. Update
the design around proxyMgr.GetConnection and the CreateVolume/DeleteVolume proxy
operations to define mTLS/server identity validation, credential handling, and
an allowlist for permitted vendor endpoints before implementation.
- Around line 442-444: Update the Cross-cluster authentication and Tenant
isolation sections to replace long-lived admin service-account tokens with
short-lived, signed, rotatable tenant-bound credentials. Add server-side
cluster-to-tenant identity mapping and enforce least-privilege, per-method
authorization so the CSI driver cannot bypass tenant OPA/JWT checks or receive
broad admin access.
- Around line 317-319: Update the StorageBackend credential design to use an
explicit secret-management path instead of inline username/password values in
data, including secure secret references and envelope encryption for stored
credentials. Define access auditing plus credential revocation and rotation
workflows, including handling compromised credentials, before permitting backend
credential storage.
- Around line 221-240: Update the CreateVolume/CreateVolumeResponse contract to
return backend-resolution data directly for the vendor proxy flow, including
endpoint, volume parameters, and credentials. Keep the persisted Volume object
and VolumeStatus limited to non-secret state and backend identifiers; do not add
these response details to Volume by default. Mark any credential fields as
write-only or redacted, and preserve existing persistence/write paths without
storing secrets.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 66c1cbf6-b737-4f0d-8c24-243e64b940c5

📥 Commits

Reviewing files that changed from the base of the PR and between 3c0fb4d and 61ef29f.

⛔ Files ignored due to path filters (2)
  • enhancements/OSAC-2872-storage-control-plane/osac-csi-flow-caas.png is excluded by !**/*.png
  • enhancements/OSAC-2872-storage-control-plane/osac-storage-components.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • enhancements/OSAC-2872-storage-control-plane/design.md

Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Clarify the Volume API call contract (two calls per operation, not one).
Add reclaim policy and cluster teardown cleanup for volume orphans. Add
idempotency mechanism (deterministic volume name from PVC). Add transient
routing fields to CreateVolumeResponse. Update Open Questions to reflect
shared VAST controller with per-tenant credential delivery as open
decision. Add spike recommendation for cross-cluster auth. Fix trailing
whitespace.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 7/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptionally detailed implementation. Full proto schemas with field types for Volume type and service. All CRUD lifecycle operations plus mount/unmount/deletion flows described with step-by-step sequences. Eight specific failure modes with recovery strategies. Three real alternatives with pros/cons/rejection rationale. Drawbacks section honestly confronts the added complexity and the in-memory volumeBackends limitation. Open questions (cross-cluster auth, credential delivery) are properly flagg
Testability 1/2 Strong test plan at all three levels: unit tests specify concrete scenarios (state transition validation, tenant forcing from JWT, tier resolution against real DB records), integration tests reference kind clusters and CSI sanity suite, and five specific E2E scenarios cover happy path and error cases. However, graduation criteria are deferred entirely ('will be defined when targeting a release') rather than specifying measurable conditions. This prevents the team from knowing when the feature is
Scope 2/2 Well-bounded scope with specific non-goals referencing Jira tickets (OSAC-984 for public API, VMaaS integration, CSI certification, multi-vendor). PRD referenced in frontmatter. Three substantive alternatives with trade-off analysis. Cross-cutting dimensions well-covered: storage (core focus), installation (Helm chart, osac-installer), tenant onboarding (AAP integration), inventory (volume records), provisioning (CSI workflow), UI (explicitly deferred with ticket reference). Documentation dimens
Architecture 2/2 Follows OSAC patterns thoroughly. Proto uses standard object shape (id, Metadata, Spec, Status) with correct spec/status ownership. Tenant isolation enforced via JWT claims and GenericDAO filtering, plus StorageClass labels. Four-repo dependency clearly enumerated (fulfillment-service, osac-csi-driver, osac-aap, osac-installer) with distinct responsibilities. Integration with existing StorageReconciler conditions (StorageBackendReady, ClusterStorageReady) preserved. Service registration follows

Verdict: A thorough, well-architected design that follows OSAC patterns closely and provides deep implementation detail, held back only by deferred graduation criteria in the test plan.

Feedback: Add concrete graduation criteria instead of deferring them — specify measurable conditions like 'all CRUD operations pass e2e, policy denial tested, no regressions in existing storage conditions, volume inventory matches vendor state for test tenants.' Also address the documentation dimension from osac-dimensions.md (even if just to defer it explicitly). Finally, consider whether Open Question 2 (credential delivery mechanism) should be resolved before merge, since option (b) would move vendor proxy logic into fulfillment-service and fundamentally change the repo split described in the proposal.

Critical (0)

None.

Important (2)

  1. Graduation criteria deferred: 'Graduation criteria will be defined when targeting a release' (line ~607) provides no measurable conditions. Specify concrete criteria such as 'All CRUD operations pass e2e, error paths tested, volume inventory consistent with vendor state, no regressions in existing StorageBackendReady/ClusterStorageReady conditions.'
  2. Open Question 2 (credential delivery, lines 559-565) could fundamentally change the architecture: option (b) moves vendor proxy logic into fulfillment-service, changing the repo split and Volume API response contract. Consider resolving this before merge or documenting both paths in the implementation details so the design remains valid regardless of the outcome.

Suggestions (4)

  1. Documentation dimension from osac-dimensions.md is not addressed. Add a line in a relevant section stating whether API reference docs, architecture docs, or user guides are in scope or explicitly deferred.
  2. Goals (lines 42-48) are implementation-focused ('Reuse existing GenericServer', 'Package as Helm chart') rather than user-visible outcomes. Consider adding one or two outcome-oriented goals such as 'Provide vendor-agnostic PVC provisioning for CaaS tenant clusters' alongside the implementation constraints.
  3. The map vendor_params field in CreateVolumeResponse (line 303) is acceptable in a private API response message, but consider documenting expected keys to help CSI driver implementers understand the contract without reading fulfillment-service internals.
  4. Consider adding a brief note on observability for the CSI node plugin (e.g., metrics for mount/unmount operations or volume_context routing decisions) to complement the controller-side metrics already defined.

Review cost

Model: claude-opus-4-6
Cost: $0.6512
Tokens: 6 in / 5.0k out
Cache: 171.7k read
Active time: 2m 2s
API calls: 0


Starting state: a tenant cluster has been provisioned via ClusterOrder, the OSAC CSI driver and VAST node plugins are deployed, and StorageClasses matching the tenant's configured tiers exist on the cluster.

**Actors:** Tenant User (creates PVC), Kubernetes (external-provisioner, external-attacher, kubelet), OSAC CSI Driver, fulfillment-service (Volume API), VAST CSI Controller, VAST Array.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarification: tenant User here is the tenant user that created the cluster, and never a specific openshift cluster.
I thought to add that so we understand that the call to the volume-api in the fulfillment-service is authenticated and authroized as one tenant user per all the storage operations for the osac-csi driver on a cluster.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Added a note that the tenant user who created the cluster is the authenticated identity for all CSI-initiated Volume API calls on that cluster.

K8s->>K8s: Create PV, bind PVC
```

The CSI controller makes two Volume API calls per provision: CreateVolume (persists record, resolves tier, checks policy, returns credentials) and UpdateVolume (records vendor volume ID, transitions to AVAILABLE).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it is the csi controller that needs to call the UpdateVolume after the vendor creation. I thinmk that should be internally reconciled by the volume-api

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I've reworked the flow so the Volume API calls the VAST controller internally and returns the completed volume. The CSI driver just makes one CreateVolume call. This also solves the credential isolation issue since vendor creds never leave the fulfillment-service.

**Deletion flow:**

1. Tenant User deletes PVC.
2. Unmount (reverse of mount): kubelet -> OSAC Node -> VAST Node (NodeUnpublishVolume, NodeUnstageVolume).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the osac.backend type coming now? we should probably persist that as a volumeAttribute on the PersistentVolume when the CSI controller see the volume in fulfillment-service is ready, and creates the PersistentVolume

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is already like that, just need to make sure

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's how it works. The Volume API populates volume_context with osac.backend, osac.volume-id, and osac.protocol in the CreateVolume response. Kubernetes stores these as spec.csi.volumeAttributes on the PV. The node plugin reads them at mount time for vendor routing. I've made this more explicit in the updated workflow.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed, see updated sequence diagram.

5. OSAC CSI Controller calls Volume API `DeleteVolume` (updates state to deleting, verifies ownership).
6. OSAC CSI Controller proxies DeleteVolume to VAST CSI Controller.
7. VAST deletes volume on array.
8. OSAC CSI Controller calls Volume API `UpdateVolume` (state: deleted).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. it is the volume-api that calls internally the vast controller
  2. I Don't think the controller needs to update the volume API again after in 5 we called DeleteVolume. I expect the volume-api to be declerative and eventually will delete or make the volume as deleted by its owne reconciler. Osac controller would need to follow the state update untill the volumme disapears, or with state=deleted.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, updated both the create and delete flows. The Volume API is now fully declarative: it handles the vendor call internally and reconciles state. The CSI driver doesn't call UpdateVolume.


**CreateVolume handler logic:**

1. Validate required fields (`storage_tier_id`, `size_gib`, `cluster_id`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assumption here is that the CSI, when calling into the CreateVolume, knows the tier already, and the storageClass has the needed tier annotation. is this right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. The StorageClass carries tier and tenant as parameters, which Kubernetes passes to the driver in req.GetParameters(). That's how the driver knows the tier.

**CreateVolume handler logic:**

1. Validate required fields (`storage_tier_id`, `size_gib`, `cluster_id`).
2. Resolve tier: call `tierResolver.Resolve(ctx, tenant, storageTierID)` which reads StorageTier and its associated StorageBackend from the DB, returns backend endpoint, protocol, and volume parameters.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can change this to tier GET, cecause tht is merely a get tier by ID, and tenant ID.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, simplified the naming. It's just a GET with a backend join.

5. Delegate to `generic.Create()` to persist the volume record.
6. Return the created volume (with backend details in status) to the CSI driver.

The CSI driver then uses the returned backend details to proxy the vendor CreateVolume call, and follows up with an UpdateVolume to set `vendor_volume_id` and transition to `AVAILABLE`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the volume API that will forward the call to the CSI backends (the vendor CSi) to create the volume. the details of thata reconciliation will be put on the Volume object.
The flow looks something like:

k8s calls csi.CreateVolume PVC123
csi calls fulfillment.CreateVolume -> return 200 OK volume status transits to CREATING and calls vendor.Create in the volume controller
poll fulfillment.GetVolume
return when volume is ready
if timeout:
k8s calls csi.CreaetVolume PVC123 (same PVC name)
csi calls fulfillmentCreateVolume return 409 conflict
poll fulfillment.GetVolume till state=READY

Flow is idempotenet, and the volume API takes care of creation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted this. The design now follows exactly this flow: CreateVolume returns 200/CREATING, reconciler handles the vendor call, CSI polls GetVolume, 409 on duplicate. See the updated sequence diagram and the new Volume Reconciler section.

Volume API now calls the VAST CSI controller internally for
CreateVolume and DeleteVolume. Vendor credentials never leave the
fulfillment-service process. The CSI driver makes a single declarative
CreateVolume call and receives the completed volume with routing
metadata. Attach/detach remains proxied by the CSI driver.

Adds vendor proxy package to fulfillment-service storage logic layer.
Updates sequence diagram, deletion flow, error handling, failure
table, alternatives, and open questions to reflect the new model.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 7/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptionally detailed implementation. Full proto schemas with field types for Volume type and service, all CRUD+Signal RPCs with HTTP annotations. CreateVolume and DeleteVolume handler logic specified step-by-step with concrete error codes (PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE). Failure handling table covers 8 specific failure modes with recovery paths and user-observable impact. Database migration details included (table structure, archived table, immutability trigger). Idempotency strate
Testability 2/2 Strong test plan with concrete scenarios at all three levels. Unit tests specify what is tested: Volume API validation and orchestration flow, tier resolution (including NOT_FOUND for nonexistent tier), policy engine (authorized/unauthorized/unassigned tier), credential manager, vendor proxy (connection errors, idempotency), migration DDL. Integration tests describe CSI sanity suite with mock fulfillment endpoint and volume lifecycle with DB records and tenant isolation verification. E2E tests e
Scope 1/2 Well-bounded scope: CaaS only, private API only, VAST vendor only. Non-goals are specific with Jira references (OSAC-984 public API, quota lifecycle, VMaaS, CSI certification, multi-vendor). Three real alternatives with clear pros/cons and rejection rationale. PRD referenced via frontmatter. However, Goals are implementation tasks ('reuse GenericServer', 'keep CSI driver thin', 'package as Helm chart') rather than user-visible outcomes. The Documentation cross-cutting dimension is not addressed
Architecture 2/2 Excellent OSAC pattern compliance. Volume proto follows standard object shape (id, Metadata, VolumeSpec, VolumeStatus) with correct spec/status ownership separation. Tenant isolation enforced via JWT claims and GenericDAO filtering, StorageClass labels include osac.openshift.io/tenant. Cross-repo impacts clearly enumerated across 4 repos (osac-csi-driver, fulfillment-service, osac-aap, osac-installer) with a clear responsibility table. Integration with existing StorageBackend/StorageTier resourc

Verdict: A thorough, implementation-ready design that follows OSAC patterns well with detailed proto schemas, failure handling, and test scenarios; the main weakness is implementation-focused goals and a missing Documentation dimension.

Feedback: Rewrite the Goals section to state user-visible outcomes rather than engineering tasks — e.g., 'Tenants can create PVCs on CaaS clusters without exposure to vendor-specific storage details' instead of 'Reuse the existing fulfillment-service GenericServer.' Add a Documentation line in the cross-cutting dimensions (even if deferred) and define graduation criteria with measurable conditions (e.g., 'All CRUD operations pass E2E, error paths tested, no regressions in existing storage conditions'). Consider typing access_mode in VolumeSpec as an enum rather than a bare string to match OSAC API conventions for constrained value sets.

Critical (0)

None.

Important (3)

  1. Goals (lines 42-47) list implementation tasks ('Reuse the existing fulfillment-service GenericServer', 'Keep the CSI driver thin') rather than user-visible outcomes. Per the rubric, goals should describe what users gain, not how it's built.
  2. Documentation cross-cutting dimension is not addressed or explicitly deferred. The design should state whether user guides, API reference, or architecture doc updates are in scope or deferred to a later milestone.
  3. Graduation criteria (line 619) are fully deferred: 'Graduation criteria will be defined when targeting a release.' Even at design stage, measurable conditions should be stated (e.g., 'all CRUD operations pass E2E, error paths tested').

Suggestions (3)

  1. VolumeSpec.access_mode is typed as string (line 243) — consider using an enum (e.g., ACCESS_MODE_READ_WRITE_ONCE, ACCESS_MODE_READ_ONLY_MANY) to match OSAC conventions for constrained value sets and enable proto validation.
  2. Add a Terminology section defining key terms (Volume API, tier resolution, vendor proxy, volume_context) for reviewers unfamiliar with CSI patterns — the Networking EP's Terminology section is a good model.
  3. Describe the Cloud Infrastructure Admin workflow for configuring storage tier access for tenants. The design covers tenant user and platform-side flows well, but the admin path for assigning tiers to tenants is implicit (OPA policy) rather than explicit.

Review cost

Model: claude-opus-4-6
Cost: $0.6821
Tokens: 6 in / 5.9k out
Cache: 172.8k read
Active time: 2m 12s
API calls: 0

Volume API is now declarative: CreateVolume persists in CREATING state
and returns immediately. A background reconciler in the fulfillment-
service picks up CREATING volumes, calls the vendor CSI controller,
and transitions to AVAILABLE. The CSI driver polls GetVolume until
ready. Same pattern for deletion (DELETING -> reconciler -> DELETED).

Adds Volume Reconciler section documenting the reconciler loop,
concurrency handling (row-level locking for multi-replica), and
restart behavior. Adds CSI driver poll loop with 409 Conflict
handling for retry idempotency.

Notes the StorageBackend schema limitation: no CSI controller
endpoint field (only management API endpoint). Single-hub
deployments use config; multi-hub needs a schema addition.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 6/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Full proto schemas with field types and validation annotations. All CRUD lifecycle operations defined in the Volumes service. Specific error codes (409, PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE). Detailed reconciler loop, CSI driver changes, and failure handling table. Risks are specific (hub SPOF, cross-cluster latency, naming migration, inventory divergence) with concrete mitigations. Open questions on auth and attach/detach credentials properly flagged with owners and impact analysis. Drawba
Testability 1/2 Excellent test plan with specific scenarios at all levels: unit tests for Volume API server, reconciler, tier lookup, policy engine, credential manager, vendor proxy, and migration; integration tests for volume lifecycle with tenant isolation and CSI sanity tests; 5 concrete E2E scenarios covering provisioning, mounting, deletion, and error paths. However, graduation criteria are effectively a placeholder: 'Graduation criteria will be defined when targeting a release' — no measurable conditions
Scope 1/2 Non-goals are specific with Jira ticket references (OSAC-984 for public API, quota lifecycle, VMaaS, CSI certification, multi-vendor). Three substantive alternatives with pros/cons and rejection rationale. PRD referenced in frontmatter. However, Goals are implementation-focused ('Reuse GenericServer', 'Keep CSI driver thin', 'Package as Helm chart') rather than user-visible outcomes — the user-facing goals (vendor abstraction, credential isolation, volume inventory) are only implied. The Documen
Architecture 2/2 Volume follows standard object shape (id, Metadata, VolumeSpec, VolumeStatus) with correct spec/status separation. Tenant isolation enforced via JWT claims and GenericDAO. Four-repo dependency table clearly identifies what each repo owns and why. Integration with existing StorageBackend/StorageTier, StorageReconciler, and AAP playbooks is well-described. Cross-repo impacts enumerated (fulfillment-service proto + osac-csi-driver + osac-aap + osac-installer). VolumeState enum is used instead of co

Verdict: A strong, deeply detailed design that follows OSAC patterns and provides thorough implementation specifics, held back by implementation-focused goals (not user-visible outcomes), a deferred graduation criteria section, and a missing Documentation dimension.

Feedback: Rewrite the Goals section to state user-visible outcomes (e.g., 'Tenants can provision persistent volumes via opaque storage tiers without vendor knowledge', 'Vendor credentials never leave the hub cluster') and move the current implementation-focused goals to an Implementation Constraints subsection. Add concrete graduation criteria — at minimum, tie them to the E2E scenarios already defined (e.g., 'All 5 E2E scenarios pass, volume reconciler handles concurrent replicas without duplicate vendor calls'). Address the Documentation dimension from osac-dimensions.md, even if only to explicitly defer it (e.g., 'Documentation deferred to GA — API is private and not user-facing').

Critical (0)

None.

Important (3)

  1. Goals section lists implementation tasks ('Reuse GenericServer', 'Keep CSI driver thin', 'Package as Helm chart') instead of user-visible outcomes. The actual user-facing goals (vendor abstraction, credential isolation, central inventory) appear only in the Summary and Motivation.
  2. Graduation criteria are entirely deferred: 'Graduation criteria will be defined when targeting a release.' The rubric expects measurable conditions. The detailed test plan already defines specific scenarios that could serve as graduation criteria.
  3. Documentation dimension from osac-dimensions.md is not addressed or explicitly deferred. Even for a private API, state whether documentation is deferred or what minimal docs are needed (e.g., runbook for volume stuck in CREATING, private API reference).

Suggestions (3)

  1. Consider using conditions instead of VolumeState enum for the Volume resource, consistent with the OSAC preference for conditions over phase enums on new resources. The 4-state lifecycle could map to conditions like 'Ready' (True/False) with reason codes.
  2. The access_mode field in VolumeSpec is a string — consider using an enum (e.g., VolumeAccessMode) for type safety and to make valid values self-documenting in the proto definition.
  3. The backend-to-CSI-controller mapping limitation (environment variable for single-hub, unresolved for multi-hub) could be surfaced as a formal Open Question rather than an inline note, to ensure it gets tracked.

Review cost

Model: claude-opus-4-6
Cost: $0.6844
Tokens: 6 in / 5.7k out
Cache: 174.9k read
Active time: 2m 3s
API calls: 0

CSI driver identity is tenant-scoped, not admin. Volume API
authorization uses a dedicated CSI role in OPA (not the admin
allowlist) enforcing tenant ownership and method-scoped access.

AAP teardown playbook now explicitly queries Volume API by cluster_id
and deletes volumes before Helm/StorageClass cleanup. Periodic orphan
scan added as a pre-GA hardening item in Risks table.

Removes duplicate failure handling row.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 7/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptionally detailed. Full proto schemas with field types and HTTP transcoding annotations. All CRUD lifecycle operations covered with specific error codes (409 Conflict, PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE). Reconciler concurrency handled via SELECT FOR UPDATE SKIP LOCKED. Five specific risks with concrete mitigations (e.g., hub SPOF mitigated by self-contained volume_context for node mounts). Three real alternatives with pros/cons/rejection rationale. Drawbacks section steel-mans the c
Testability 1/2 Test plan is strong: unit tests specify 14+ concrete test areas across fulfillment-service and CSI driver (reconciler state transitions, tier lookup failures, policy denial, vendor proxy idempotency, CSI controller poll/409 handling, node routing). Integration tests describe real DB records and csi-test suite with mock endpoint. E2E tests describe 5 user-observable scenarios including error path (nonexistent StorageClass). However, graduation criteria are deferred ('will be defined when targetin
Scope 2/2 Clear boundaries. Summary is 3 sentences covering what, why, and key capabilities. Five specific non-goals with Jira ticket references (OSAC-984, etc.). PRD referenced in frontmatter and body. Three real alternatives with rationale. Cross-cutting dimensions well-covered: CaaS in scope, VMaaS explicitly excluded, storage/provisioning/installation/tenant-onboarding/inventory/E2E all addressed, UI explicitly deferred to OSAC-984. Documentation dimension is a minor gap (not explicitly addressed or d
Architecture 2/2 Follows all OSAC patterns. Standard object shape (id, Metadata, VolumeSpec, VolumeStatus) with correct spec/status ownership — spec has user-controlled desired state (storage_tier_id, size_gib, access_mode, cluster_id), status has system-controlled observed state (state, vendor_volume_id, backend_id, protocol). Tenant isolation via GenericDAO tenant filtering and JWT claims, StorageClasses labeled with osac.openshift.io/tenant. Cross-repo impacts clearly enumerated in a table (fulfillment-servic

Verdict: A thorough, well-architected design that follows OSAC patterns closely and provides deep implementation detail; the only material gap is deferred graduation criteria with no measurable conditions.

Feedback: Define concrete graduation criteria — e.g., 'Dev Preview: all CRUD operations pass e2e on a single-tenant kind cluster; Tech Preview: multi-tenant tenant isolation verified, reconciler handles 100+ concurrent volumes, stale volume detection exercised; GA: 30-day production soak with no orphaned volumes.' Also explicitly address or defer the Documentation dimension from osac-dimensions.md — the Support Procedures section partially covers operational docs, but user-facing documentation for the private Volume API and CSI driver operational guide should be scoped or deferred. Consider specifying the reconciler's poll interval and stale threshold as concrete values (or at least ranges) rather than 'N seconds' and 'threshold.'

Critical (0)

None.

Important (2)

  1. Graduation criteria are deferred with no measurable conditions ('will be defined when targeting a release'). This is the single gap preventing a Testability score of 2. Define concrete, stage-specific conditions (what must pass at Dev Preview vs. Tech Preview vs. GA).
  2. Documentation dimension from osac-dimensions.md is not explicitly addressed or deferred. The private Volume API, CSI driver deployment guide, and storage troubleshooting procedures need documentation scoping — the Support Procedures section covers some of this but doesn't commit to docs deliverables.

Suggestions (4)

  1. Reconciler operational parameters (poll interval, stale timeout threshold, retry backoff) are left as 'N seconds' and 'threshold'. Specifying concrete defaults (e.g., '10s poll interval, 15-minute stale threshold, exponential backoff capped at 5 minutes') would help reviewers assess operational impact and give implementers a starting point.
  2. VolumeState uses a phase enum rather than conditions, which the OSAC conventions prefer for new resources. This is defensible for a private API with a simple 4-state machine, but adding a brief justification for the choice (e.g., 'Conditions are unnecessary for this linear state machine with no concurrent sub-states') would preempt reviewer questions.
  3. The access_mode field in VolumeSpec is a plain string. Using an enum (ACCESS_MODE_READ_WRITE_ONCE, etc.) would provide type safety and align with the proto convention of preferring enums for fixed-value fields.
  4. Persona roles in the workflow descriptions could be more explicit — Cloud Infrastructure Admin's role in configuring StorageBackends and Cloud Provider Admin's role in policy/tier assignment are implied but not called out in the workflow steps.

Review cost

Model: claude-opus-4-6
Cost: $0.6805
Tokens: 6 in / 5.5k out
Cache: 175.5k read
Active time: 2m 5s
API calls: 0

Commits to osac-{tenant}-{tier} naming convention (e.g.,
osac-acme.com-gold). Drops vendor name and protocol from the
StorageClass name. Protocol remains on the storage-protocol label.
Removes Open Question 3 (resolved).

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 7/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Deeply detailed implementation with full proto schemas for Volume type and Volumes service including field types and REST transcoding annotations. All CRUD lifecycle operations covered (Create, Get, List, Update, Delete, Signal). CreateVolume and DeleteVolume handler logic specified step-by-step with specific error codes (409, PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE). Failure handling table covers 9 specific failure modes with what-happens, recovery, and user-observes columns. Risks are specif
Testability 1/2 Test plan is strong with specific scenarios at all three levels. Unit tests enumerate 14+ specific behaviors (validation, state transitions, tenant isolation, tier lookup, policy, credentials, vendor proxy, migration, CSI controller/node behavior). Integration tests describe kind cluster infrastructure and CSI sanity suite with mock fulfillment endpoint. E2E tests list 5 concrete user-observable scenarios. However, graduation criteria are deferred: 'Graduation criteria will be defined when targe
Scope 2/2 Clear boundaries with PRD referenced in frontmatter. Summary is concise (3 sentences covering what, why, key capabilities). Non-goals are specific with Jira references (OSAC-984 for public Volume API, VMaaS, CSI certification, multi-vendor beyond VAST). Three real alternatives with pros/cons and rejection rationale (standalone service, client-side orchestration, do nothing). Goals are implementation constraints appropriate for a design document per the template. Cross-cutting dimensions from osa
Architecture 2/2 Sound architectural decisions consistent with OSAC patterns. Volume proto follows standard object shape (id, Metadata, VolumeSpec, VolumeStatus) with correct spec/status ownership. Tenant isolation enforced via JWT claims and GenericDAO filtering (same mechanism as all fulfillment-service resources). StorageClasses labeled with osac.openshift.io/tenant. Cross-repo dependencies clearly identified across 4 repos (osac-csi-driver, fulfillment-service, osac-aap, osac-installer) with rationale for ea

Verdict: A thorough, well-architected design that follows OSAC patterns closely, provides deep implementation detail with full proto schemas and specific error handling, and clearly scopes boundaries with real alternatives -- held back from a perfect score only by deferred graduation criteria.

Feedback: Define concrete graduation criteria instead of deferring them -- even preliminary conditions like 'all CRUD operations pass e2e with tenant isolation, error paths tested, no regressions in existing storage conditions' would satisfy the requirement. The access_mode field in VolumeSpec should be an enum rather than a bare string to ensure validation and documentation of valid values. The Volume reconciler's poll interval, backoff strategy, and stale timeout threshold should be specified as configurable defaults rather than left implicit.

Critical (0)

None.

Important (3)

  1. Graduation criteria are deferred ('will be defined when targeting a release') rather than providing measurable conditions. Even early-stage designs benefit from concrete criteria like 'all CRUD operations pass e2e, error paths tested, no regressions in existing storage tests' to guide implementation.
  2. The Documentation dimension from osac-dimensions.md is not addressed or explicitly deferred. The design should state whether user-facing documentation (admin guides for CSI driver deployment, support runbooks) is in scope for this milestone or deferred.
  3. The Volume reconciler introduces a new pattern (DB poll loop) for the fulfillment-service but does not specify the poll interval, backoff strategy on vendor failures, or the stale timeout threshold value. These should be defined as configurable defaults.

Suggestions (4)

  1. The access_mode field in VolumeSpec is a bare string; consider defining a VolumeAccessMode enum (READ_WRITE_ONCE, READ_ONLY_MANY, READ_WRITE_MANY) for better validation and documentation.
  2. Open Question 2 (attach/detach credential handling) is architecturally significant -- consider whether this should be resolved before the design merges, as the chosen approach could change the Volume API surface (option c adds attach/detach RPCs).
  3. Consider adding a Terminology section to formally define terms like 'tier resolution', 'volume_context', 'vendor proxy', and 'meta-driver' that are used throughout but introduced in context rather than upfront.
  4. The observability section lists metrics but does not define alerting thresholds (e.g., what value of osac_volumes_by_state with state=CREATING would indicate a problem).

Review cost

Model: claude-opus-4-6
Cost: $0.7573
Tokens: 7 in / 5.9k out
Cache: 250.6k read
Active time: 2m 26s
API calls: 0

Document the mapping from VolumeStatus fields to volume_context keys
in the CSI driver controller section: backend_id -> osac.backend,
vendor_volume_id -> osac.volume-id, protocol -> osac.protocol.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 6/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Deep technical detail: full proto schemas with field types, all CRUD lifecycle ops covered, specific error codes per failure mode (409, PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE), reconciler with concurrency handling (row-level locking) and restart recovery, concrete risk mitigations. Two open questions (cross-cluster auth, attach/detach credentials) are honestly flagged with owners and blocking impact rather than hand-waved. Drawbacks section steel-mans the complexity argument.
Testability 1/2 Test plan is specific at each level: unit tests enumerate validation, state transitions, error paths, and concurrency; integration tests specify tenant isolation and CSI sanity suite with mock; e2e tests describe 5 concrete user-observable flows (provision, create PVC, mount+I/O, delete+cleanup, error case). However, graduation criteria are explicitly deferred ('will be defined when targeting a release') with no measurable conditions provided, preventing a score of 2.
Scope 1/2 PRD referenced in frontmatter and summary. Non-goals are specific with Jira tickets (OSAC-984, quota, VMaaS, CSI cert, multi-vendor). Three real alternatives with detailed trade-offs. However, goals are implementation tasks ('Reuse GenericServer patterns', 'Keep CSI driver thin') rather than user-visible outcomes. Documentation dimension from osac-dimensions.md is not addressed at all — no mention of admin guides, architecture docs, or API reference updates for a new storage control plane. Cloud
Architecture 2/2 Proto schema follows standard object shape (id, Metadata, VolumeSpec, VolumeStatus) with correct spec/status ownership. Tenant isolation enforced via JWT claims, GenericDAO filtering, and OPA policies. Cross-repo dependencies clearly enumerated across 4 repos with responsibilities and ordering. Integration with existing StorageBackend, StorageTier, and StorageReconciler conditions well-described. StorageClass naming migration has clear strategy (new clusters only). Volume reconciler introduces a

Verdict: A strong, deeply technical design that follows OSAC architectural patterns and provides thorough implementation detail, held back from a higher score by implementation-focused goals, a missing Documentation dimension, and deferred graduation criteria.

Feedback: Reframe the Goals section as user-visible outcomes rather than implementation tasks — e.g., 'Tenants can create persistent volumes using opaque storage tiers without vendor-specific knowledge' instead of 'Reuse GenericServer patterns.' Add a Documentation subsection addressing what admin guides, architecture docs, or API reference updates are needed (or explicitly defer them with a ticket). Provide at least preliminary graduation criteria with measurable conditions — e.g., 'All CRUD operations pass e2e, error paths tested, no regressions in existing storage conditions' — rather than fully deferring to a future release.

Critical (0)

None.

Important (4)

  1. Goals section lists implementation tasks ('Reuse the existing fulfillment-service GenericServer', 'Keep the CSI driver thin', 'Package as Helm chart') rather than user-visible outcomes. Design EP goals should describe what the feature achieves from a user/operator perspective.
  2. Documentation dimension from osac-dimensions.md is not addressed: no mention of user-facing documentation, admin guides, architecture doc updates, or API reference for the new storage control plane. Either address documentation needs or explicitly defer with a rationale.
  3. Graduation criteria are fully deferred ('will be defined when targeting a release') with no measurable conditions. Even preliminary criteria (e.g., 'All CRUD operations pass e2e, error paths tested, no regressions in existing storage conditions') would strengthen the design.
  4. Cloud Infrastructure Admin persona (who manages StorageBackends and storage tiers) is implied throughout but never explicitly named in workflow descriptions. The Workflow Description section focuses exclusively on the Tenant User flow.

Suggestions (3)

  1. Add a Terminology section defining key terms (volume inventory, tier resolution, vendor proxy, volume_context) upfront — the networking EP benchmark demonstrates this pattern and reviewers expect it.
  2. Integration test section could specify infrastructure more explicitly: does the volume lifecycle test use a kind cluster with real DB, or standalone PostgreSQL? The fulfillment-service integration test pattern (kind + TLS + Keycloak) is established but not referenced here.
  3. Consider whether VolumeState enum should use conditions instead, per OSAC convention for new resources. The design uses a phase-style enum (CREATING, AVAILABLE, DELETING, DELETED), which may be justified for a private API but should be explicitly called out as a deliberate choice.

Review cost

Model: claude-opus-4-6
Cost: $0.7729
Tokens: 7 in / 6.5k out
Cache: 250.8k read
Active time: 2m 32s
API calls: 0

Volume lifecycle now follows the established OSAC pattern: the
fulfillment-service creates a Volume CR on the hub, the osac-operator
reconciles it (calls the vendor CSI controller), and a feedback
controller syncs status back.

Key changes:
- Volume CRD in osac-operator with conditions (VendorProvisioned,
  PVCBound), phases (Progressing, Ready, Failed, Deleting)
- Dual-controller pattern: resource controller + feedback controller
- Vendor controller discovery via in-cluster DNS (vast.osac-csi-backend.svc)
- PVC/PV tracking: spec.pvcRef (input), status.pvcRef/pvRef (operator
  confirmed via cross-cluster GET + requeue), annotations for OpenShift UI
- ClusterOrder finalizer (volume-cleanup) blocks deletion until volumes
  processed using PV persistentVolumeReclaimPolicy
- Credentials derived from existing hub Secret (vast-tenant-config-{tenant})
- Cross-cluster auth: tenant user credentials for first release
- Replaced PNG diagrams with Mermaid
- Removed vendor REST adapter references

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@akshaynadkarni
akshaynadkarni marked this pull request as ready for review July 27, 2026 20:07
@openshift-ci
openshift-ci Bot requested a review from CrystalChun July 27, 2026 20:07
@github-actions

github-actions Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 7/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptionally detailed. Full proto schemas with field types and validation rules. All CRUD lifecycle operations covered with specific error codes (NOT_FOUND, PERMISSION_DENIED, UNAVAILABLE, 409 Conflict). Comprehensive failure handling table with 9 distinct failure modes and concrete recovery paths. Risks are specific and technical ('concurrent subnet allocation may cause CIDR overlap'-caliber) with actionable mitigations. Drawbacks section honestly addresses added complexity and the in-memory v
Testability 1/2 Test plan is strong — specific scenarios at each level (unit: 'Create validates required fields, forces tenant from JWT, persists in CREATING state, returns 409 on duplicate name'; integration: 'Volume lifecycle with tenant isolation, tier resolution against real DB records'; e2e: 'Create PVC, verify Volume CR on hub, verify inventory record'). CSI sanity test suite included. However, graduation criteria are essentially deferred: 'will be defined when targeting a release' with only vague staging
Scope 2/2 Well-bounded. Summary is concise (4 sentences). Non-goals are specific with Jira references (OSAC-984 for public API, VMaaS storage, CSI certification, multi-vendor beyond VAST). PRD is properly referenced in frontmatter and body. Alternatives section is exemplary — four real alternatives with honest trade-offs. Cross-cutting dimensions mostly addressed: storage (core), installation (Helm chart, umbrella chart, AAP), tenant onboarding (AAP deploys CSI driver), provisioning (full lifecycle), UI (
Architecture 2/2 Excellent alignment with OSAC patterns. Proto follows standard object shape (id, Metadata, VolumeSpec, VolumeStatus) with clean spec/status ownership split. Dual-controller pattern (resource controller + feedback controller) matches ComputeInstance and ClusterOrder. Conditions (VendorProvisioned, PVCBound) plus phases (Progressing, Ready, Failed, Deleting) follow existing convention. Tenant isolation enforced via JWT claims, GenericDAO tenant filtering, and OPA policies. Cross-repo impacts clear

Verdict: A thorough, well-architected design that follows OSAC patterns consistently across all four repos, with deep implementation detail, comprehensive failure handling, and strong alternatives analysis — held back from a perfect score only by deferred graduation criteria.

Feedback: The main gap is graduation criteria: replace 'will be defined when targeting a release' with measurable conditions (e.g., 'All CRUD volume operations pass e2e, CSI sanity suite passes, tenant isolation verified, no regressions in existing storage conditions'). Consider reframing Goals as user-visible outcomes ('Tenants can provision persistent volumes through standard PVC workflows without vendor-specific knowledge') rather than implementation constraints ('Reuse GenericServer'). Finally, address the Documentation dimension from osac-dimensions.md — either state what documentation is needed (API reference, architecture updates) or explicitly defer it.

Critical (0)

None.

Important (3)

  1. Graduation criteria are deferred ('will be defined when targeting a release') — this is effectively a placeholder. Add measurable conditions tied to the test plan scenarios already described (e.g., 'All CRUD operations pass e2e with tenant isolation verified, CSI sanity suite passes, error paths tested, no regressions in existing StorageBackendReady/ClusterStorageReady conditions').
  2. Goals section lists implementation constraints ('Reuse the existing fulfillment-service GenericServer, GenericDAO', 'Keep the CSI driver thin') rather than user-visible outcomes. These are valid design constraints but belong in Implementation Details. Goals should state what users/operators gain (e.g., 'Tenants provision persistent volumes through standard Kubernetes PVC workflows without vendor-specific knowledge').
  3. Documentation dimension from osac-dimensions.md is not addressed or explicitly deferred. The design should state whether API reference docs, architecture diagram updates, or user guides are in scope or deferred to a follow-up.

Suggestions (4)

  1. Add a Terminology section (following the networking EP pattern) to formally define terms like 'Volume CR', 'vendor CSI controller', 'hub cluster', 'storage tier', and 'volume_context' upfront — the design uses these consistently but a formal glossary helps reviewers.
  2. Consider adding negative E2E test scenarios: unauthorized tenant attempting wrong-tier access, PVC with nonexistent tier (beyond just nonexistent StorageClass), and cluster teardown with mixed Retain/Delete reclaim policies.
  3. The RBAC/Tenancy section partially duplicates the Security Considerations section (CSI driver identity and OPA policy updates appear in both). Consider consolidating to reduce redundancy and potential for drift.
  4. The open question about cross-cluster TLS notes 'unencrypted gRPC matching the POC' — consider whether this should be a non-goal with a tracking ticket rather than an open question, since the design explicitly defers it.

Review cost

Model: claude-opus-4-6
Cost: $0.8294
Tokens: 9 in / 5.5k out
Cache: 411.6k read
Active time: 2m 18s
API calls: 0

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@enhancements/OSAC-2872-storage-control-plane/design.md`:
- Line 65: Update the “Architecture: Volume lifecycle components” heading from
level five to level three, using the proposal’s existing heading hierarchy.
- Line 662: Update the fenced code block in the design document to include an
explicit language identifier, using text for plain-text content, while
preserving the block’s existing contents.
- Around line 542-546: Update the DeleteVolume handler logic to be idempotent:
after verifying tenant ownership, return success for volumes already in DELETING
or DELETED state, and for missing volumes, while transitioning only active
volumes to DELETING. Document these outcomes explicitly so CSI retries never
fail or strand PV cleanup.
- Around line 193-196: Standardize the tier identifier contract across the
design: choose one canonical representation and apply it consistently to the
proto, StorageClass parameter, validation, policy lookup, API flow, and
persisted volume record. Update all references to storage_tier, storage_tier_id,
tier names, and ID-based lookups—including the cited sections—so request
handling and persistence use the same identifier semantics.
- Around line 193-195: Define a single immutable cluster UUID as the ownership
and cleanup key in the volume lifecycle documented around CreateVolume and the
teardown flows. Replace interchangeable uses of clusterID, cluster_id, and
spec.cluster with this canonical UUID, while retaining cluster names only as
non-identity metadata; apply the same consistency to the referenced sections.
- Around line 730-733: Update the volume_context and VolumeStatus field
definitions to use the proto’s exact backend field name, replacing
status.backend_id with status.backend. Distinguish the OSAC fulfillment-service
volume UUID from the vendor_volume_id, and populate osac.volume-id with the OSAC
UUID used for CR tracking while retaining vendor_volume_id as the vendor
identifier.
- Around line 560-564: The volume reconciler must process deletion transitions
immediately rather than relying on the periodic sync. Extend the event handling
described in the volume event subscription to recognize the event emitted by
DeleteVolume when a record enters DELETING, then update or delete the
corresponding Volume CR through the existing hubClient flow while preserving
periodic reconciliation as a fallback.
- Around line 634-636: Define an explicit bounded cleanup path for the Failed
state with VendorProvisioned=True and PVCBound=False: after a binding timeout,
transition the volume to DELETING and invoke the existing vendor-volume removal
flow, or specify an equivalent administrative cleanup workflow with ownership,
trigger, and deadline. Apply the same behavior to the corresponding state
definition around the other referenced section, while preserving the existing
terminal Failed behavior for volumes that were never provisioned.
- Around line 405-411: Update the operator RBAC requirements for ClusterOrder
finalizer handling to include get, watch, update, and patch permissions on
ClusterOrder resources, including finalizer updates. Also document and verify
the required cross-cluster kubeconfig/credential access used to inspect PV
reclaim policies during ClusterOrder deletion.
- Line 115: Define the tenant-side authentication flow for the vendor node
plugin, including how it receives non-reusable iSCSI connection and
authentication material without exposing reusable vendor credentials; otherwise
revise the claim that tenant clusters have no vendor credentials. Keep the
statements consistent across the tenant data-plane description and the
referenced deployment and node-plugin sections.
- Around line 562-566: Update the VolumeSpec-to-Volume CR creation flow to
explicitly propagate the authenticated volume record’s tenant value into the
osac.openshift.io/tenant annotation. Populate this mapping server-side before
hubClient.Create(), and ensure reconciliation preserves the authenticated tenant
rather than accepting a client-supplied value.
- Around line 534-538: Define a machine-readable duplicate-volume response for
the 409 path: either add a GetVolume-by-name flow that returns the existing
volume ID, or specify a structured gRPC conflict error detail carrying that ID.
Document how the CSI driver extracts and uses the ID, and apply the same
behavior to the corresponding duplicate-handling section.
- Around line 364-366: Update the Volume idempotency design to use a globally
unique key derived from the full PVC identity—tenant, cluster, namespace, and
name or UID—instead of PVCReference.name alone. Apply the same derived key to
both VolumeSpec.pvc_ref and the active-name uniqueness constraint, ensure
retries for the same PVC remain idempotent without cross-cluster collisions, and
document this contract near the CreateVolume retry behavior.
- Line 164: Update the attach/detach flow represented by the `csictrl
-->|"attach/detach"| vendors` diagram edge to document a reachable tenant-side
CSI controller endpoint, including its DNS/service identity, namespace, network
policy, authentication, TLS, and failure behavior; alternatively relocate the
proxying to the hub-side and document those same operational details there.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3217e2bd-9a3c-480c-a0c4-002f42cbd69a

📥 Commits

Reviewing files that changed from the base of the PR and between 61ef29f and f687f1a.

📒 Files selected for processing (1)
  • enhancements/OSAC-2872-storage-control-plane/design.md

Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Fix tier identifier consistency (storage_tier_id -> storage_tier).
Add ClusterOrder RBAC for volume-cleanup finalizer. Make DeleteVolume
idempotent (success for DELETING, DELETED, not-found). Process
deletion events immediately (subscribe to all volume events, not just
CREATED/SIGNALED). Make tenant annotation propagation explicit on
Volume CR. Add language identifier to fenced code block. Fix stale
volume_context field reference (backend_id -> backend).

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 6/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptionally detailed. Full proto schemas with field types and validation annotations for both volume_type.proto and volumes_service.proto. All CRUD lifecycle operations covered with specific error codes (PERMISSION_DENIED, NOT_FOUND, 409 Conflict). Comprehensive failure handling table covering 9 failure modes with concrete recovery paths (e.g., 'Operator retries via RunProvisioningLifecycle with backoff'). Drawbacks section steel-mans the complexity argument honestly. Four real alternatives wi
Testability 1/2 Test plan is strong: unit tests specify validation logic, state transitions, and error paths per component (fulfillment-service, osac-operator, osac-csi-driver). Integration tests name infrastructure (kind cluster, envtest, csi-test suite with mock endpoint). E2E tests describe 6 concrete user-observable scenarios including error paths. However, graduation criteria are a placeholder: 'Graduation criteria will be defined when targeting a release.' This counts against the score per the rubric's tr
Scope 1/2 PRD is referenced via frontmatter and inline link. Non-goals are specific with Jira ticket references (OSAC-984, etc.). Alternatives section is exemplary with 4 real alternatives. However, Goals are implementation tasks ('Reuse the existing fulfillment-service GenericServer', 'Follow the existing OSAC resource lifecycle pattern') rather than user-visible outcomes. The Documentation dimension from osac-dimensions.md is neither addressed nor explicitly deferred, which is a gap per the rubric (sile
Architecture 2/2 Excellent OSAC pattern compliance. Standard object shape (id, Metadata, VolumeSpec, VolumeStatus) in proto. Spec/status ownership is correct (spec = desired state, status = observed state). Dual-controller pattern (resource controller + feedback controller) matches ComputeInstance/ClusterOrder. Tenant isolation via osac.openshift.io/tenant annotation propagated from JWT claims. Conditions (VendorProvisioned, PVCBound) preferred for lifecycle state with clear phase/condition matrix. Cross-repo im

Verdict: A thorough and architecturally sound design that follows OSAC patterns consistently across all four repositories, with detailed proto schemas, comprehensive failure handling, and strong test scenarios, held back from a higher score by placeholder graduation criteria and implementation-focused goals.

Feedback: Two concrete improvements: (1) Replace the Goals section with user-visible outcomes ('Tenants can provision persistent volumes on CaaS clusters without vendor awareness', 'Platform admins have central volume inventory and policy enforcement') and move the current implementation-focused goals to the Proposal section as design constraints. (2) Add measurable graduation criteria, e.g., 'All CRUD operations pass e2e with VAST backend, tenant isolation verified (tenant A cannot see tenant B volumes), no regressions in existing storage conditions.' Also add a Documentation subsection addressing or deferring user-facing docs (API reference, admin guides for storage tier configuration).

Critical (0)

None.

Important (3)

  1. Goals section (lines 42-47) lists implementation tasks ('Reuse the existing fulfillment-service GenericServer', 'Follow the existing OSAC resource lifecycle pattern', 'Keep the CSI driver thin') rather than user-visible outcomes. Per the scope rubric, goals should describe what users or personas gain, not how the system is built.
  2. Graduation criteria (lines 1032-1033) are a placeholder: 'Graduation criteria will be defined when targeting a release.' The rubric treats placeholder-only sections as counting against the dimension score. Add measurable conditions (e.g., 'All CRUD operations pass e2e, tenant isolation verified, no regressions in existing storage conditions').
  3. Documentation dimension from osac-dimensions.md is not addressed or deferred. The design should state whether user-facing documentation (admin guide for storage tier configuration, API reference for the private Volume API) is in scope for this milestone or explicitly deferred.

Suggestions (3)

  1. Add a Terminology section defining key terms (Volume CR vs volume record, tier resolution, volume_context, vendor CSI controller) to match the pattern established by the Networking EP and flagged in review-patterns.md.
  2. The Open Questions section acknowledges unencrypted gRPC for cross-cluster auth. Consider strengthening the Security Considerations section to explicitly call out this known gap and its risk boundary (acceptable for dev preview, must-fix for GA) rather than relying solely on the Open Questions section.
  3. Consider whether Volume CRs should carry an osac.openshift.io/owner-reference annotation pointing to the ClusterOrder, consistent with the resource hierarchy pattern used by other OSAC resources. Currently, the cluster association is via spec.cluster and the volume-cleanup finalizer on ClusterOrder, but the owner-reference annotation is the standard OSAC convention for expressing parent-child relationships.

Review cost

Model: claude-opus-4-6
Cost: $0.6901
Tokens: 6 in / 4.7k out
Cache: 184.1k read
Active time: 1m 51s
API calls: 0

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@enhancements/OSAC-2872-storage-control-plane/design.md`:
- Line 901: Update the Operator RBAC requirement to explicitly grant Secret get
access in the osac-system namespace, matching the tenant-credential mapping
described elsewhere in the design. If retaining “storage config namespace,”
define it consistently as osac-system and use that alias throughout the
document.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 342a4446-19a1-48df-a24f-8c9ef1d25904

📥 Commits

Reviewing files that changed from the base of the PR and between f687f1a and 7ffb442.

📒 Files selected for processing (1)
  • enhancements/OSAC-2872-storage-control-plane/design.md

Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Fix heading levels for architecture/components diagrams (h5 -> h3).
Clarify volume name is PVC-UID-based from external-provisioner (globally
unique, no collision risk). Add ListVolumes with name filter for 409
duplicate resolution. Add three open questions: immutable cluster
identity (UUID solution proposed), attach/detach routing, data-plane
credentials for node mount (CHAP).

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 6/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Deep technical detail: full proto schemas with field types and enums, CRD Go types with kubebuilder annotations, all CRUD lifecycle operations covered with specific error codes (409, PERMISSION_DENIED, NOT_FOUND, UNAVAILABLE), comprehensive failure handling table with 9 failure modes, 4 well-argued alternatives. Drawbacks section steel-mans the hub dependency argument. Open questions are genuine unknowns with proposed solutions, not hand-waving.
Testability 1/2 Strong test plan broken down by component at unit, integration, and E2E levels with specific scenarios (e.g., 'Create validates required fields, forces tenant from JWT, persists in CREATING state. Returns 409 on duplicate name'). E2E covers 6 user-observable scenarios. However, graduation criteria are deferred: 'Graduation criteria will be defined when targeting a release' — no concrete measurable conditions provided.
Scope 1/2 PRD referenced via frontmatter and inline link. Non-goals are specific with Jira references. Four real alternatives with rejection rationale. UX explicitly deferred to OSAC-984. However, goals are implementation-focused ('Reuse the existing fulfillment-service GenericServer', 'Keep the CSI driver thin') rather than user-visible outcomes. Documentation dimension from osac-dimensions.md is silently ignored — not addressed or explicitly deferred.
Architecture 2/2 Follows all major OSAC patterns: standard object shape, spec/status ownership, dual-controller pattern (resource + feedback), finalizer lifecycle, tenant isolation annotation, pluggable vendor routing via in-cluster DNS. Cross-repo dependencies clearly enumerated across 5 repos. Conditions (VendorProvisioned, PVCBound) with detailed phase/condition matrix. Minor gap: missing osac.openshift.io/owner-reference annotation on Volume CR, though volumes lack a clear parent resource in the hierarchy.

Verdict: A thorough and well-architected design that follows OSAC patterns consistently, provides deep implementation detail with proto schemas and CRD types, and covers all lifecycle operations — held back from a higher score by implementation-focused goals, a deferred graduation criteria placeholder, and a silently ignored documentation dimension.

Feedback: Rewrite the Goals section to state user-visible outcomes (e.g., 'Tenants can provision block storage on CaaS clusters without exposure to vendor-specific details') rather than implementation decisions. Add concrete graduation criteria with measurable conditions (e.g., 'All CRUD operations pass E2E, error paths tested, no regressions in existing storage conditions'). Address the documentation dimension from osac-dimensions.md — either specify what docs are needed (user guide for storage tiers, API reference for private Volume API, architecture doc updates) or explicitly defer it with a Jira reference.

Critical (0)

None.

Important (6)

  1. Goals section (lines 42-48) lists implementation decisions ('Reuse the existing fulfillment-service GenericServer', 'Keep the CSI driver thin') rather than user-visible outcomes. Rewrite as what users/admins observe: 'Tenants can provision block storage without vendor exposure', 'Cloud Infrastructure Admins can view volume inventory centrally'.
  2. Graduation criteria (lines 1057-1059) are a placeholder: 'Graduation criteria will be defined when targeting a release.' The rubric requires concrete measurable conditions. Add specific criteria like 'All CRUD operations pass E2E, error paths tested, no regressions in existing StorageBackendReady/ClusterStorageReady conditions.'
  3. Documentation dimension from osac-dimensions.md is silently ignored. No mention of user guides, API reference updates, or architecture doc changes. Address or explicitly defer with a Jira reference.
  4. RBAC/Tenancy section (lines 896-905) is a near-verbatim duplicate of the CSI driver identity block in Security Considerations (lines 869-876). Remove the duplication.
  5. Missing osac.openshift.io/owner-reference annotation on the Volume CR. The critical rule states 'Never skip tenant isolation metadata (osac.openshift.io/tenant, osac.openshift.io/owner-reference annotations) in new resources.' The tenant annotation is present but owner-reference is absent. If volumes have no parent resource, state that explicitly.
  6. Open Questions section has a numbering error — two items labeled '3' (lines 999 and 1006). Renumber the data-plane credentials question to '4'.

Suggestions (3)

  1. Add a Terminology section following the networking EP pattern. Key terms like 'tier resolution', 'feedback controller', 'vendor CSI controller', 'volume_context' are used consistently but could benefit from upfront definition.
  2. Consider documenting why Phase is used instead of conditions-only for the Volume CRD. The rubric notes 'Conditions used for lifecycle state (preferred over phase enums for new resources).' The design follows existing OSAC convention (same as ClusterOrder) but doesn't justify the choice.
  3. The attach/detach routing open question (lines 999-1004) is architecturally significant — whether all operations go through the Volume API or require a direct cross-cluster connection changes the security model. Consider promoting this to a design decision with a recommended approach rather than leaving it fully open.

Review cost

Model: claude-opus-4-6
Cost: $0.6093
Tokens: 6 in / 7.3k out
Cache: 215.0k read
Active time: 2m 30s
API calls: 0

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 7/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptionally detailed: full proto schemas with field types, all CRUD lifecycle operations covered with sequence diagrams, 9-entry failure mode table with specific error codes and recovery paths, 4 real alternatives with trade-off analysis, drawbacks section steel-mans the complexity argument. Open questions are honest and scoped with owners/impact.
Testability 1/2 Strong test plan with specific scenarios at unit (Create validates, 409 on duplicate, tier lookup, policy engine), integration (tenant isolation, envtest, CSI sanity suite), and E2E (6 specific scenarios) levels. However, graduation criteria are entirely deferred ('will be defined when targeting a release') rather than specifying measurable conditions, which caps the score at 1.
Scope 2/2 Clear 4-sentence summary. 5 specific non-goals with Jira links. PRD referenced in frontmatter and body. 4 real alternatives with rejection rationale. Cross-cutting dimensions well-covered (Storage, Provisioning, Tenant Onboarding, Installation, E2E Testing, Inventory, UI deferred with ticket). Minor gap: Documentation dimension not addressed or deferred. Goals are implementation-focused rather than user-visible outcomes, but PRD reference compensates.
Architecture 2/2 Follows OSAC patterns precisely: standard object shape (id, Metadata, Spec, Status), dual-controller pattern (resource + feedback), GenericServer/GenericDAO reuse, pg_notify reconciler, tenant isolation via JWT + GenericDAO. Cross-repo impacts enumerated across 5 repos with dependency table. Spec/status ownership correct. Conditions with phase matrix follow convention. StorageClass naming migration has clear compatibility path.

Verdict: A thorough, well-structured design that follows OSAC patterns closely and provides exceptional implementation detail across 5 repositories; the only material gap is deferred graduation criteria in the test plan.

Feedback: Add concrete graduation criteria — specify measurable conditions for each stage (Dev Preview, Tech Preview, GA), such as 'all CRUD operations pass E2E, error paths tested, no regressions in existing storage tests, volume inventory matches vendor state for >95% of volumes.' Address the Documentation dimension explicitly — even if deferred, state what docs are needed and when. Consider reframing at least some Goals as user-visible outcomes (e.g., 'Tenants can create persistent volumes without exposure to vendor-specific details') alongside the implementation goals.

Critical (0)

None.

Important (3)

  1. Graduation criteria deferred entirely ('will be defined when targeting a release') — the rubric requires measurable conditions per stage. Add specific criteria like: Dev Preview requires all CRUD E2E passing; Tech Preview requires multi-tenant isolation verified; GA requires orphan scan and TLS hardening complete.
  2. Documentation dimension from osac-dimensions.md is not addressed or explicitly deferred — silence on a relevant dimension is a gap per the review rubric. State what user-facing docs (user guides, API reference, architecture updates) are needed and whether they're in scope or deferred.
  3. Goals section lists only implementation goals (reuse GenericServer, follow lifecycle pattern, keep CSI driver thin) rather than user-visible outcomes. While acceptable in a design document that references its PRD, adding at least one user-visible goal would strengthen the Motivation section.

Suggestions (4)

  1. Add a Terminology section defining key terms (Volume CR vs volume record, hub cluster, vendor controller, tier resolution) — the networking EP's Terminology section is cited as a best practice in review-patterns.md.
  2. Open Question 2 (immutable cluster identity) has architectural implications for the Volume proto spec and teardown logic — consider resolving this before implementation to avoid a proto schema change later.
  3. E2E test plan could add explicit error/negative scenarios: policy denial (unauthorized tenant creates PVC), vendor failure (array unreachable during provisioning), and cluster teardown with active volumes.
  4. The RBAC/Tenancy section (lines 896-909) repeats the CSI driver identity and OPA policy content from Security Considerations almost verbatim — consolidate to avoid drift between the two sections.

Review cost

Model: claude-opus-4-6
Cost: $0.7143
Tokens: 6 in / 5.3k out
Cache: 185.7k read
Active time: 2m 2s
API calls: 0

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
enhancements/OSAC-2872-storage-control-plane/design.md (1)

117-165: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align the topology with the VAST-only scope.

This diagram deploys NetApp and Pure node/controllers, while the non-goals explicitly exclude multi-vendor support beyond VAST. Either remove those components for this release or label them as future architecture; otherwise the deployment scope and acceptance criteria are ambiguous.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@enhancements/OSAC-2872-storage-control-plane/design.md` around lines 117 -
165, Update the “Components: OSAC storage and CSI deployment topology” diagram
to reflect the VAST-only release scope: remove the NetApp and Pure node
plugins/controllers and their topology connections, or clearly label them as
future architecture. Keep the VAST components and existing VAST-related
relationships unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@enhancements/OSAC-2872-storage-control-plane/design.md`:
- Around line 364-366: Document the vendor volume name/ID recovery contract in
the retry and duplicate CreateVolume sections: require the external-provisioner
PVC-UID name to reach the CSI CreateVolume request unchanged, and define
tenant-scoped ListVolumes CEL name-filter behavior, including exactly one
matching volume. Specify the handling for no match or multiple matches so
recovery resumes the existing volume without creating duplicates.

---

Outside diff comments:
In `@enhancements/OSAC-2872-storage-control-plane/design.md`:
- Around line 117-165: Update the “Components: OSAC storage and CSI deployment
topology” diagram to reflect the VAST-only release scope: remove the NetApp and
Pure node plugins/controllers and their topology connections, or clearly label
them as future architecture. Keep the VAST components and existing VAST-related
relationships unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 25c71628-16a6-4ff8-8d3b-8e54c240aba7

📥 Commits

Reviewing files that changed from the base of the PR and between 7ffb442 and 854f018.

📒 Files selected for processing (1)
  • enhancements/OSAC-2872-storage-control-plane/design.md

Comment thread enhancements/OSAC-2872-storage-control-plane/design.md Outdated
**Cons:** Tenants see vendor-specific StorageClasses. Vendor credentials stored on tenant clusters. No central inventory. No policy enforcement point.
**Rejected because:** Does not meet the PRD requirements for vendor abstraction, credential isolation, or volume inventory.

## Open Questions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avishayt @rgolangh PTAL at the Open Questions.


## Summary

This design introduces a vendor-agnostic storage layer for OSAC CaaS tenant clusters. A single CSI driver (`csi.osac.openshift.io`) presents opaque storage tiers to tenants, while a storage logic layer inside the fulfillment-service handles tier resolution, policy enforcement, credential management, and volume inventory. The CSI driver is a thin gRPC client that delegates every storage decision to the fulfillment-service via a private Volume API, then proxies volume operations to vendor CSI controllers running on the hub cluster. See [PRD](prd.md) for detailed requirements.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the google doc we discussed a non-OSAC name to leave the door open to make this a generic driver with a community around it. I suggested facade.csi.io, shadow.csi.io, or broker.csi.io - but am open to other options.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment here.

We can discuss naming separately and adjust the design once we have agreement.


## Summary

This design introduces a vendor-agnostic storage layer for OSAC CaaS tenant clusters. A single CSI driver (`csi.osac.openshift.io`) presents opaque storage tiers to tenants. The fulfillment-service handles tier resolution, policy enforcement, and volume inventory via a private Volume API. The osac-operator reconciles Volume CRs on the hub cluster, calling vendor CSI controllers to create and delete volumes on storage arrays. See [PRD](prd.md) for detailed requirements.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed a generic name for the CSI driver, like facade-csi instead of csi.osac.openshift.io.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thing is that a csi driver also needs to say a vendor in its name.

Also the osac project is upstream first and open source, and osac isn't a product name.

btw I just saw that the convention {name}.csi.{domain}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looked at how other CSI drivers are named (ebs.csi.aws.com, pd.csi.storage.gke.io, rook-ceph.rbd.csi.ceph.com). Roy is right about the naming order: the convention is {name}.csi.{domain}.

Updated all references in the design to osac.csi.openshift.io.

I don't have a strong opinion on whether the name should be OSAC-specific or generic. Happy to defer to you two on this. If the name changes, one of us can update the design accordingly.

@akshaynadkarni akshaynadkarni Aug 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Comment thread enhancements/OSAC-2872-storage-control-plane/design.md
Rename CSI driver from csi.osac.openshift.io to osac.csi.openshift.io
to follow the {name}.csi.{domain} convention used by production CSI
drivers (ebs.csi.aws.com, pd.csi.storage.gke.io, etc.).

Add volume snapshots and clones to Non-Goals (Avishay's comment).

Expand the duplicate CreateVolume recovery section to specify the
name pass-through contract (CSI spec guarantee) and ListVolumes
filter edge cases (0 matches = fatal, >1 = impossible due to
uniqueness constraint).

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

AI Design Review: EP-151

Score: 7/8 | Verdict: PASS

Criterion Score Notes
Feasibility 2/2 Exceptional implementation depth. Full proto schemas with field types for Volume type and service. All lifecycle operations (create, get, list, update, delete, signal, mount, unmount) are specified with numbered steps, error codes, and actor roles. Failure handling table covers 9 failure modes with behavior, recovery, and user-observable impact. Drawbacks section steel-mans the complexity argument. Four open questions are honestly documented with ownership and impact. The attach/detach routing g
Testability 1/2 Test plan is strong with specific scenarios at each level: unit tests enumerate exact cases per component (Volume API validation, reconciler CR creation, CSI controller polling, node routing), integration tests name infrastructure (kind cluster, envtest, CSI sanity suite with mock fulfillment-service), and E2E tests describe 6 concrete user-observable scenarios including error cases and annotation verification. However, graduation criteria are absent — 'will be defined when targeting a release'
Scope 2/2 Clear boundaries with PRD referenced via frontmatter. Six specific non-goals with Jira links (OSAC-984 for public API, VMaaS, snapshots, multi-vendor, CSI certification, quota lifecycle). Four real alternatives with detailed pros/cons/rejection rationale — the strongest alternatives section seen in OSAC EPs. Goals lean implementation-oriented ('Reuse the existing fulfillment-service GenericServer') rather than user-visible, but this is a design doc where implementation framing is reasonable. Doc
Architecture 2/2 Follows OSAC patterns consistently. Volume proto uses standard object shape (id, Metadata, VolumeSpec, VolumeStatus). Spec contains desired state, status contains observed state. Controller uses provisioning.RunProvisioningLifecycle() with dual-controller pattern (resource + feedback). Tenant isolation via osac.openshift.io/tenant annotation on Volume CRs, enforced by GenericDAO and OPA. Cross-repo impacts enumerated in a table (5 repos with 'what' and 'why'). Deploy order specified. StorageClas

Verdict: Strong design with exceptional implementation depth spanning 5 repos, clear architectural alignment with OSAC patterns, and thorough failure handling — held back from a higher score only by absent graduation criteria in the test plan.

Feedback: Add concrete graduation criteria to the test plan — e.g., 'All CRUD operations pass E2E on a real VAST backend, error paths tested, no regressions in existing storage conditions, volume inventory matches vendor array state.' Either add osac.openshift.io/owner-reference annotation on Volume CRs or explicitly explain why the cleanup finalizer on ClusterOrder is preferred over the standard ownership pattern. Remove the duplicated RBAC/Security content (CSI driver identity and OPA policy updates appear verbatim in both Security Considerations and RBAC/Tenancy sections).

Critical (0)

None.

Important (5)

  1. Graduation criteria absent: 'Graduation criteria will be defined when targeting a release' is a deferral, not a condition. The test plan is detailed but graduation criteria must state measurable conditions (e.g., 'all CRUD operations pass E2E, error paths tested, no regressions in existing storage conditions'). This is the sole reason testability scores 1.
  2. Missing osac.openshift.io/owner-reference annotation on Volume CRs: Architecture patterns require owner-reference annotations for parent-child relationships, but Volume CRs use spec.cluster and a cleanup finalizer on ClusterOrder instead. The alternative mechanism works but deviates from the standard pattern without explanation. Either add the annotation or document why the standard pattern doesn't apply here.
  3. Documentation dimension not addressed: osac-dimensions.md requires each relevant dimension to be addressed or explicitly deferred. A new API, CRD, and CSI driver likely need API reference documentation, architecture docs updates, and support procedure documentation. The dimension is silently omitted.
  4. RBAC/Security content duplicated: The 'CSI driver identity' invariants and 'OPA policy updates' paragraphs appear word-for-word in both 'Security Considerations' and 'RBAC / Tenancy' sections. Consolidate into one location and cross-reference from the other.
  5. Goals are implementation tasks rather than user-visible outcomes: All six goals describe implementation approaches ('Reuse the existing fulfillment-service GenericServer', 'Follow the existing OSAC resource lifecycle pattern') rather than user/operator outcomes. Consider adding at least one goal that states what users gain (e.g., 'Enable CaaS tenants to provision block storage via standard Kubernetes PVCs without exposure to vendor-specific details').

Suggestions (3)

  1. Add a Terminology section (per the Networking EP pattern) defining key terms: Volume (fulfillment-service record vs Volume CR), StorageTier, StorageBackend, OSAC CSI driver vs vendor CSI controller, vendor volume vs OSAC volume. The design uses these consistently but a formal section helps reviewers and implementers.
  2. Clarify the relationship between spec.pvc_ref.cluster and spec.cluster — these appear to carry the same value for PVC-driven volumes. If they can differ, explain when; if not, consider removing the redundancy.
  3. Open question Bump actions/checkout from 4 to 5 #2 (immutable cluster identity) has a ready solution described in the question itself (use ClusterOrder UUID). Consider promoting this to a design decision rather than leaving it open, since it affects the proto schema and multiple components.

Review cost

Model: claude-opus-4-6
Cost: $0.7022
Tokens: 4.5k in / 6.2k out
Cache: 364.7k read
Active time: 2m 25s
API calls: 0

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@enhancements/OSAC-2872-storage-control-plane/design.md`:
- Line 367: The Duplicate CreateVolume 409 recovery flow must bound zero-match
ListVolumes failures instead of returning them to Kubernetes indefinitely.
Update the CreateVolume recovery logic to limit reconciliation attempts, then
persist or emit a reconciliation failure and trigger the established repair
alert; only return CSI retryable errors for transient API unavailability, while
treating the data-integrity failure as terminal after the bound.
- Line 367: Update the “Duplicate CreateVolume (retry after timeout)” section to
distinguish CSI guarantees from external-provisioner behavior: state only that
the CO reuses CreateVolumeRequest.name and provisioning is idempotent by name,
and qualify pvc-{PVC-UID} as an external-provisioner convention rather than a
CSI guarantee. If retaining the PVC-UID naming requirement, add the relevant
sidecar/version-specific coverage.
- Line 844: Update the Volume API provisioning flow described near StorageClass
creation so the tenant is derived from the authenticated CSI identity, not
trusted from the mutable StorageClass tenant parameter. Reject requests when the
parameter is present and does not match the authenticated tenant, and use
matching or absent parameters only as a consistency check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 89c5c716-fe91-4288-b97f-c428e2cfb262

📥 Commits

Reviewing files that changed from the base of the PR and between 854f018 and 0beca26.

📒 Files selected for processing (1)
  • enhancements/OSAC-2872-storage-control-plane/design.md


**Vendor volume creation failure:** The operator Volume controller retries via the standard `provisioning.RunProvisioningLifecycle()` pattern (backoff, retry, status update). The volume name is generated by external-provisioner from the PVC's Kubernetes UID (e.g., `pvc-{PVC-UID}`), which is globally unique across clusters and namespaces. The vendor CSI CreateVolume is idempotent by name per the CSI spec.

**Duplicate CreateVolume (retry after timeout):** If Kubernetes retries and the CSI driver calls CreateVolume again for the same PVC, external-provisioner sends the same PVC-UID-based name. The Volume API returns 409 Conflict (volume already exists). The CSI driver resolves the existing volume ID by calling `ListVolumes` with a CEL filter on the volume name, then polls `GetVolume(id)` until the volume reaches AVAILABLE. The name pass-through is guaranteed by the CSI spec: external-provisioner generates the volume name from `pvc-{PVC-UID}` and passes it unchanged through `CreateVolumeRequest.name` to the CSI driver, which forwards it to the Volume API. The `ListVolumes` name filter must return exactly one match (the volume name has a unique constraint in the database). Zero matches indicates a data integrity issue (the 409 said the volume exists, but it cannot be found); the CSI driver treats this as a fatal error and returns it to Kubernetes for retry. Multiple matches are impossible due to the uniqueness constraint.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound the 409 recovery failure path.

A 409 followed by zero ListVolumes matches is explicitly a data-integrity failure, not a normal transient retry. Returning it to Kubernetes for unlimited retries can leave the PVC Pending indefinitely and repeatedly load the API. After bounded recovery attempts, persist/emit a reconciliation failure and alert for repair; reserve CSI retries for transient unavailability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@enhancements/OSAC-2872-storage-control-plane/design.md` at line 367, The
Duplicate CreateVolume 409 recovery flow must bound zero-match ListVolumes
failures instead of returning them to Kubernetes indefinitely. Update the
CreateVolume recovery logic to limit reconciliation attempts, then persist or
emit a reconciliation failure and trigger the established repair alert; only
return CSI retryable errors for transient API unavailability, while treating the
data-integrity failure as terminal after the bound.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 3 'external-provisioner|pvc-\{?PVC|CreateVolumeRequest|provisioner' .

Repository: osac-project/enhancement-proposals

Length of output: 20348


🌐 Web query:

Kubernetes external-provisioner csi-provisioner pvc-{UID} CreateVolume name pass-through CSI spec

💡 Result:

In the Kubernetes CSI external-provisioner, the volume name passed to the CSI CreateVolume request is generated by the provisioner itself using a configurable prefix and the PersistentVolumeClaim (PVC) UID [1][2][3]. By default, this name follows the format pvc-{UID}, where the prefix "pvc" is configurable via the --volume-name-prefix flag [4][3]. Regarding "name pass-through" and CSI specification compliance: 1. Volume Naming: The CSI specification requires the CreateVolumeRequest to include a Name field, which serves as a unique identifier for the volume being provisioned. The external-provisioner manages this requirement by automatically generating a unique name based on the PVC's UID to ensure global uniqueness and prevent collisions [5][2][6]. This name is not "passed through" from the PVC object directly as the primary identifier; rather, it is computed by the provisioner [2][3]. 2. Metadata Pass-through: If you require the actual Kubernetes PVC name, namespace, or the resulting PV name to be available to your CSI driver during the CreateVolume call, the external-provisioner provides a mechanism via the --extra-create-metadata flag [7][4]. When enabled, the provisioner injects the following keys into the parameters map of the CreateVolumeRequest [8][7]: - csi.storage.k8s.io/pvc/name - csi.storage.k8s.io/pvc/namespace - csi.storage.k8s.io/pv/name These parameters allow CSI drivers to associate the underlying storage resource with the specific Kubernetes objects that requested it [9]. This is the standard, authoritative approach for passing Kubernetes-specific metadata into the CSI CreateVolume process [7][4].

Citations:


🌐 Web query:

"CSI spec" "CreateVolumeRequest" "Name" "CSI driver"

💡 Result:

In the Container Storage Interface (CSI) specification, the Name field within the CreateVolumeRequest message is a required string that identifies the volume to be provisioned [1][2]. Key details regarding the Name field: 1. Function: It serves as the unique identifier for the volume request [3]. According to the CSI specification, the CreateVolume operation must be idempotent [3]. If a volume with the specified name already exists and meets the requirements defined in the other fields (such as capacity_range, volume_capabilities, and parameters), the CSI driver must return a successful response rather than attempting to create a new volume [3]. 2. Usage in Kubernetes: When using a CSI driver with Kubernetes, the Kubernetes external-provisioner (a common sidecar container) typically generates this name [4][5]. It often derives the name from the PersistentVolumeClaim (PVC) name to ensure consistency and prevent collisions [4][3]. 3. Implementation: In the generated Go code for the CSI specification, this field is accessed via the GetName method on the CreateVolumeRequest struct [1]. It is important to note that while the Name field is used to identify the volume, it is distinct from any opaque parameters passed in the parameters field [6][7]. Some implementations may pass additional metadata, such as the PVC name or namespace, within the parameters map to help the driver contextually manage the volume, particularly if the driver needs to relate the storage resource back to a specific Kubernetes workload [7][4][5].

Citations:


🌐 Web query:

github.com container-storage-interface spec CreateVolumeRequest Name idempotent CSI

💡 Result:

In the Container Storage Interface (CSI) specification, the CreateVolumeRequest operation is required to be idempotent [1][2]. The name field in CreateVolumeRequest is the primary mechanism used by the Container Orchestrator (CO) to ensure this idempotency [3][1]. Key requirements and behaviors for CreateVolume idempotency include: 1. Idempotency Guarantee: If a volume with the specified name already exists, and it is compatible with the requested accessibility_requirements, capacity_range, volume_capabilities, and parameters, the CSI plugin must return a successful response (0 OK) containing the existing volume's details [4][5]. 2. Error Handling for Incompatibility: If a volume with the same name exists but is incompatible with the requested parameters (e.g., different capacity range, capabilities, accessibility requirements, or source snapshot), the plugin must return an ALREADY_EXISTS error code [6][4]. 3. CO Responsibilities: The CO generates the name to identify the storage space. If a CreateVolume call fails (e.g., due to a network timeout), the CO may safely retry the request using the same name to determine if the volume was successfully provisioned or to retrieve its volume_id [3][1]. 4. Plugin Obligations: The plugin should ensure that multiple CreateVolume calls with the same name do not result in the provisioning of multiple physical volumes [3][1]. If a plugin cannot enforce this, it risks creating orphaned or redundant volumes [3][1]. The name field serves a dual purpose: it acts as a tool for achieving idempotency and, if the underlying storage system allows it, it may optionally serve as the permanent identifier for the provisioned storage [3][7].

Citations:


Distinguish the CSI contract from external-provisioner specifics.

The CSI spec guarantees CreateVolumeRequest.name is reused by the CO and that provisioning must be idempotent by name, but pvc-{PVC-UID} is an external-provisioner convention, not the spec. Either replace that guarantee with the CSI idempotency guarantee, or add the sidecar/version-specific coverage before documenting this behavior as required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@enhancements/OSAC-2872-storage-control-plane/design.md` at line 367, Update
the “Duplicate CreateVolume (retry after timeout)” section to distinguish CSI
guarantees from external-provisioner behavior: state only that the CO reuses
CreateVolumeRequest.name and provisioning is idempotent by name, and qualify
pvc-{PVC-UID} as an external-provisioner convention rather than a CSI guarantee.
If retaining the PVC-UID naming requirement, add the relevant
sidecar/version-specific coverage.

1. Deploy the OSAC CSI driver Helm chart to the target cluster (instead of installing the VAST CSI operator via OLM).
2. Deploy the VAST CSI controller as a separate Deployment on the hub cluster (in `osac-csi-backend` namespace) if not already running. The service name matches the provider name (e.g., `vast`), so it's reachable at `vast.osac-csi-backend.svc.cluster.local`.
3. Deploy the VAST node plugin as a co-located container in the OSAC CSI node DaemonSet on the target cluster.
4. Create StorageClasses with provisioner `osac.csi.openshift.io` and parameters `tier=<tierName>`, `tenant=<tenantName>`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Bind tenant to the authenticated identity.

tenant=<tenantName> is mutable StorageClass configuration and must not authorize cross-tenant operations. The Volume API should derive the tenant from the authenticated CSI identity, reject mismatches with the parameter, and use the parameter only as a consistency check.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@enhancements/OSAC-2872-storage-control-plane/design.md` at line 844, Update
the Volume API provisioning flow described near StorageClass creation so the
tenant is derived from the authenticated CSI identity, not trusted from the
mutable StorageClass tenant parameter. Reject requests when the parameter is
present and does not match the authenticated tenant, and use matching or absent
parameters only as a consistency check.

@rgolangh

Copy link
Copy Markdown
Contributor

/lgtm
/approve

@openshift-ci

openshift-ci Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: akshaynadkarni, rgolangh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:
  • OWNERS [akshaynadkarni,rgolangh]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot
openshift-merge-bot Bot merged commit 740f273 into osac-project:main Jul 28, 2026
5 checks passed
akshaynadkarni added a commit to akshaynadkarni/enhancement-proposals that referenced this pull request Jul 28, 2026
Publish and unpublish operations (ControllerPublishVolume,
ControllerUnpublishVolume) now route through the fulfillment-service
instead of proxying directly to the vendor CSI controller. This gives
the CSI driver a single cross-cluster connection to the
fulfillment-service for all controller operations.

Introduces osac.internal.v1.StorageControlPlane, a new gRPC service
in a new proto package restricted to OSAC components only (not
accessible to CSP admins, unlike osac.private.v1). The fulfillment-
service orchestrates vendor calls through the operator, following the
same async pattern as create/delete.

This resolves the former Open Question 3 (attach/detach routing).

Also addresses CodeRabbit review comments from PR osac-project#151:
- Distinguish CSI spec idempotency guarantee from external-provisioner
  pvc-{PVC-UID} naming convention
- Bound the 409 recovery failure path (terminal error after retries)
- Document StorageClass tenant parameter as a consistency check against
  the authenticated CSI identity (JWT), not a source of authorization
- Deduplicate CSI identity text between Security and RBAC sections

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
// PVCRef is set when the volume was triggered by a PVC creation.
// Empty for API-driven volume creation (OSAC-984).
// +kubebuilder:validation:Optional
PVCRef *PVCReferenceType `json:"pvcRef,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strange here. What if I create a volume via API and then attach it to a cluster? I would expect this information to possibly be on a VolumeAttachment but definitely not here.

Phase PhaseType `json:"phase,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
VendorVolumeID string `json:"vendorVolumeID,omitempty"`
Backend string `json:"backend,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Should not be in the public API when we create it (I know it's out of scope)

Comment on lines +615 to +619
PVCRef *PVCReferenceType `json:"pvcRef,omitempty"`

// PVRef is set after the PV is created on the tenant cluster.
// +kubebuilder:validation:Optional
PVRef *PVReferenceType `json:"pvRef,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of VolumeAttachment? Not here...

@openshift-ci openshift-ci Bot removed the lgtm label Jul 30, 2026
empovit pushed a commit to empovit/osac-enhancement-proposals that referenced this pull request Aug 2, 2026
Publish and unpublish operations (ControllerPublishVolume,
ControllerUnpublishVolume) now route through the fulfillment-service
instead of proxying directly to the vendor CSI controller. This gives
the CSI driver a single cross-cluster connection to the
fulfillment-service for all controller operations.

Introduces osac.internal.v1.StorageControlPlane, a new gRPC service
in a new proto package restricted to OSAC components only (not
accessible to CSP admins, unlike osac.private.v1). The fulfillment-
service orchestrates vendor calls through the operator, following the
same async pattern as create/delete.

This resolves the former Open Question 3 (attach/detach routing).

Also addresses CodeRabbit review comments from PR osac-project#151:
- Distinguish CSI spec idempotency guarantee from external-provisioner
  pvc-{PVC-UID} naming convention
- Bound the 409 recovery failure path (terminal error after retries)
- Document StorageClass tenant parameter as a consistency check against
  the authenticated CSI identity (JWT), not a source of authorization
- Deduplicate CSI identity text between Security and RBAC sections

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants