Skip to content

OCPBUGS-59404: Allow VolumeSnapshot restore when parent PVC is deleted#16447

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
sg00dwin:OCPBUGS-59404-volumesnapshot-restore
May 14, 2026
Merged

OCPBUGS-59404: Allow VolumeSnapshot restore when parent PVC is deleted#16447
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
sg00dwin:OCPBUGS-59404-volumesnapshot-restore

Conversation

@sg00dwin
Copy link
Copy Markdown
Member

@sg00dwin sg00dwin commented May 14, 2026

Analysis / Root cause:

The "Restore as new PVC" modal for VolumeSnapshots gates the StorageClass dropdown and Size input on pvcStorageClassName — a value derived exclusively from the parent PVC. When the parent PVC is deleted, useK8sGet returns a 404, pvcStorageClassName becomes undefined, and both fields permanently show skeleton loaders. The Restore button stays disabled because no storage class can be selected.

The snapshot already carries all necessary metadata via annotations (storage class, access modes, volume mode) set at creation time, plus status.restoreSize for the size — but the modal's rendering conditionals never fall through to use them.

Solution description:

Added two computed booleans to restore-pvc-modal.tsx:

  • pvcNotFound: detects when the PVC fetch completed with a 404
  • formReady: true when PVC is confirmed deleted OR when PVC and its StorageClass have loaded

Changed three rendering conditionals:

  1. StorageClass dropdown gate: !pvcStorageClassName || !scResourceLoaded!formReady
  2. When PVC is deleted, StorageClass dropdown shows all available storage classes (unfiltered) with the annotated value pre-selected
  3. Size input gate: !!pvcStorageClassName && scResourceLoadedformReady, with isInputDisabled skipping SC-based checks when PVC is not found

When the parent PVC exists, pvcNotFound=false and formReady reduces to the original condition — zero behavioral change.

Screenshots with fix:
Restore as new PVC form
New PVC details

Test setup:

A cluster with CSI snapshot support (e.g., AWS with gp3-csi and csi-aws-vsc). Adjust storageClassName and volumeSnapshotClassName for your environment.

# Create test namespace and PVC
oc create namespace snapshot-restore-test

oc apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
  namespace: snapshot-restore-test
spec:
  storageClassName: gp3-csi
  accessModes: [ReadWriteOnce]
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
EOF

# PVC needs a consumer to bind (WaitForFirstConsumer)
oc apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: snapshot-restore-test
spec:
  containers:
    - name: test
      image: registry.access.redhat.com/ubi9/ubi-minimal:latest
      command: ["sleep", "infinity"]
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: test-pvc
EOF

# Wait for PVC to bind
oc get pvc -n snapshot-restore-test -w
# Ctrl+C when STATUS = Bound

# Create snapshot
oc apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: test-snapshot
  namespace: snapshot-restore-test
spec:
  volumeSnapshotClassName: csi-aws-vsc
  source:
    persistentVolumeClaimName: test-pvc
EOF

# Wait for snapshot to be ready
oc get volumesnapshot -n snapshot-restore-test -w
# Ctrl+C when READYTOUSE = true

Test cases:

  1. Regression check (PVC exists):

    • Go to Storage > VolumeSnapshots in project snapshot-restore-test
    • Kebab menu on test-snapshot > "Restore as new PVC"
    • Verify: StorageClass dropdown shows gp3-csi, Access mode and Volume mode selectors render, Size shows 1 GiB, Restore button is enabled
    • Cancel the modal
  2. Bug fix verification (PVC deleted):

    oc delete pod test-pod -n snapshot-restore-test
    oc delete pvc test-pvc -n snapshot-restore-test
    • Kebab menu on test-snapshot > "Restore as new PVC"
    • Verify: StorageClass dropdown renders with available storage classes (pre-selects gp3-csi), Access mode and Volume mode selectors render, Size shows 1 GiB, Restore button is enabled
    • Click Restore — a new PVC should be created successfully
  3. Cleanup:

    oc delete namespace snapshot-restore-test

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced the restore PVC modal to handle missing source PVCs. The form now displays all necessary controls and allows restoration to proceed using snapshot annotations and metadata, even when the original PVC no longer exists.

@openshift-ci-robot openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels May 14, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-59404, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Analysis / Root cause:

The "Restore as new PVC" modal for VolumeSnapshots gates the StorageClass dropdown and Size input on pvcStorageClassName — a value derived exclusively from the parent PVC. When the parent PVC is deleted, useK8sGet returns a 404, pvcStorageClassName becomes undefined, and both fields permanently show skeleton loaders. The Restore button stays disabled because no storage class can be selected.

The snapshot already carries all necessary metadata via annotations (storage class, access modes, volume mode) set at creation time, plus status.restoreSize for the size — but the modal's rendering conditionals never fall through to use them.

Solution description:

Added two computed booleans to restore-pvc-modal.tsx:

  • pvcNotFound: detects when the PVC fetch completed with a 404
  • formReady: true when PVC is confirmed deleted OR when PVC and its StorageClass have loaded

Changed three rendering conditionals:

  1. StorageClass dropdown gate: !pvcStorageClassName || !scResourceLoaded!formReady
  2. When PVC is deleted, StorageClass dropdown shows all available storage classes (unfiltered) with the annotated value pre-selected
  3. Size input gate: !!pvcStorageClassName && scResourceLoadedformReady, with isInputDisabled skipping SC-based checks when PVC is not found

When the parent PVC exists, pvcNotFound=false and formReady reduces to the original condition — zero behavioral change.

Screenshots with fix:
Restore as new PVC form
New PVC details

Test setup:

A cluster with CSI snapshot support (e.g., AWS with gp3-csi and csi-aws-vsc). Adjust storageClassName and volumeSnapshotClassName for your environment.

# Create test namespace and PVC
oc create namespace snapshot-restore-test

oc apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: test-pvc
 namespace: snapshot-restore-test
spec:
 storageClassName: gp3-csi
 accessModes: [ReadWriteOnce]
 volumeMode: Filesystem
 resources:
   requests:
     storage: 1Gi
EOF

# PVC needs a consumer to bind (WaitForFirstConsumer)
oc apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
 name: test-pod
 namespace: snapshot-restore-test
spec:
 containers:
   - name: test
     image: registry.access.redhat.com/ubi9/ubi-minimal:latest
     command: ["sleep", "infinity"]
     volumeMounts:
       - name: data
         mountPath: /data
 volumes:
   - name: data
     persistentVolumeClaim:
       claimName: test-pvc
EOF

# Wait for PVC to bind
oc get pvc -n snapshot-restore-test -w
# Ctrl+C when STATUS = Bound

# Create snapshot
oc apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
 name: test-snapshot
 namespace: snapshot-restore-test
spec:
 volumeSnapshotClassName: csi-aws-vsc
 source:
   persistentVolumeClaimName: test-pvc
EOF

# Wait for snapshot to be ready
oc get volumesnapshot -n snapshot-restore-test -w
# Ctrl+C when READYTOUSE = true

Test cases:

  1. Regression check (PVC exists):
  • Go to Storage > VolumeSnapshots in project snapshot-restore-test
  • Kebab menu on test-snapshot > "Restore as new PVC"
  • Verify: StorageClass dropdown shows gp3-csi, Access mode and Volume mode selectors render, Size shows 1 GiB, Restore button is enabled
  • Cancel the modal
  1. Bug fix verification (PVC deleted):
oc delete pod test-pod -n snapshot-restore-test
oc delete pvc test-pvc -n snapshot-restore-test
  • Kebab menu on test-snapshot > "Restore as new PVC"
  • Verify: StorageClass dropdown renders with available storage classes (pre-selects gp3-csi), Access mode and Volume mode selectors render, Size shows 1 GiB, Restore button is enabled
  • Click Restore — a new PVC should be created successfully
  1. Cleanup:
oc delete namespace snapshot-restore-test

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.

@openshift-ci openshift-ci Bot requested review from Leo6Leo and rhamilto May 14, 2026 18:23
@openshift-ci openshift-ci Bot added the component/core Related to console core functionality label May 14, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

The change modifies the PVC restore modal to handle cases where the source PVC no longer exists. It introduces a pvcNotFound state flag and derives form readiness logic that permits the modal to render form controls (StorageClass dropdown and size input) either when the PVC is missing or when PVC metadata and StorageClass information are available. The size input's disabled state is updated to conditionally depend on PVC existence, allowing form interaction when the PVC has been deleted. This enables restoration workflows using snapshot annotations and status as fallback data sources.

🚥 Pre-merge checks | ✅ 12
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: enabling VolumeSnapshot restore functionality when the parent PVC has been deleted, directly addressing the bug fix in the changeset.
Description check ✅ Passed The description comprehensively covers root cause analysis, solution details, screenshots, detailed test setup with reproducible commands, regression and bug-fix test cases, and browser conformance validation.
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.
Stable And Deterministic Test Names ✅ Passed PR modifies only restore-pvc-modal.tsx, a React/TypeScript component. The custom check is for Ginkgo test names, not applicable to non-test component code. No test files are included.
Test Structure And Quality ✅ Passed PR modifies only React/TypeScript component (restore-pvc-modal.tsx), contains no Ginkgo test code. Custom check for Ginkgo test quality is not applicable.
Microshift Test Compatibility ✅ Passed Custom check not applicable: PR modifies only TypeScript/React frontend component (restore-pvc-modal.tsx). No Ginkgo e2e tests or Go files were added/modified. Check targets Go e2e tests specifically.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PR modifies only a React/TypeScript component (restore-pvc-modal.tsx). No Ginkgo e2e tests are added. Custom check is inapplicable.
Topology-Aware Scheduling Compatibility ✅ Passed This check does not apply—the PR modifies only a React/TypeScript UI component in the console frontend. No deployment manifests, operator code, or scheduling constraints are introduced.
Ote Binary Stdout Contract ✅ Passed Check not applicable. PR modifies only React/TypeScript frontend component, not Go test binaries or OTE infrastructure that OTE Binary Stdout Contract covers.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR modifies only a React/TypeScript component (restore-pvc-modal.tsx) with no Ginkgo e2e tests added. The check applies only when new Ginkgo tests are introduced, so it is not applicable here.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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
`@frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx`:
- Around line 83-93: The code treats any "loaded but no PVC object" (pvcNotFound
computed from pvcResourceLoaded && !pvcResource) as deletion which can
misclassify non-404 errors; update the logic that computes pvcNotFound to only
be true when the GET hook indicates an explicit 404 (check the hook's error
payload field name, e.g., error.status or error.code) returned by the useK8sGet
call for the PVC (use the same variable holding the error/status), and then use
that gated pvcNotFound when deriving formReady so transient/API/RBAC errors
won't set formReady true.
🪄 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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 2ed0bfd6-8878-41cc-b433-fe2ea06b485c

📥 Commits

Reviewing files that changed from the base of the PR and between c9d3418 and 4b52d47.

📒 Files selected for processing (1)
  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/**/*.{ts,tsx}: Never import from package index files (barrel imports) like @console/shared in new code, as they create circular dependencies and slow builds. Import from specific file paths instead.
Never use backticks in i18n t() function calls as the i18n parser cannot extract keys from template literals. Use single or double quotes instead.
Never import from deprecated packages or use code marked with @deprecated TSdoc tag in new code.

Files:

  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
frontend/**/*.{ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Never use absolute URLs or paths. The console runs behind a proxy under an arbitrary path.

Files:

  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
**/*

📄 CodeRabbit inference engine (STYLEGUIDE.md)

Use lowercase dash-separated names for all files (to avoid git issues with case-insensitive file systems)

Files:

  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (STYLEGUIDE.md)

**/*.{ts,tsx,js,jsx}: New code MUST be written in TypeScript, not JavaScript
Run the linter and follow all rules defined in .eslintrc
Never use absolute paths in code; the app should be able to run behind a proxy under an arbitrary path
Use PascalCase for component file names, kebab-case for utility files, and *.spec.ts(x) for test files

Use camelCase for variable names in TypeScript and JavaScript files

**/*.{ts,tsx,js,jsx}: Any usage of i18next's TFunction (rather than react-i18next's TFunction) must be performed inside a function or component.
Don't use backticks inside of a TFunction. Our code parser will not automatically pick up the keys that contain backticks. Use single or double quotes instead.
Specify possible static values in comments for dynamic i18next keys that can't be interpolated by i18next-parser, such as t(key), t('key' + id), or t(key${id}).

Files:

  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (STYLEGUIDE.md)

**/*.{ts,tsx}: Prefer functional programming patterns and immutable data structures in TypeScript/JavaScript
Use React functional components with hooks instead of class components in TypeScript
Use React hooks and Context API for state management (migrating away from legacy Redux/Immutable.js)
Use existing hooks from console-shared when possible (useK8sWatchResource, useUserSettings, etc.)
Use k8s resource hooks for data fetching and consoleFetchJSON for HTTP requests in TypeScript
Place plugin routes in plugin-specific route files
Check existing types in console-shared before creating new types
Use SCSS modules co-located with components, PatternFly design system components, and avoid any SCSS/CSS if possible
Follow WCAG 2.1 AA standards for accessibility; use semantic HTML, ARIA labels where needed, ensure keyboard navigation, and test with screen readers
Use useTranslation('namespace') hook with key format for translation keys in TypeScript
Use ErrorBoundary components and graceful degradation patterns for error handling in TypeScript
Use useCallback to memoize callbacks and prevent unnecessary re-renders in React
Use useMemo for expensive filtering and computations to prevent re-computation on every render
Use React.lazy() to lazy load heavy components
Avoid using the any type in TypeScript; suggest proper type definitions instead
Check that null/undefined are properly handled in TypeScript (e.g., string | undefined)
Verify exported types for reusable components in TypeScript
Reuse types from existing components rather than duplicating type definitions in component props
Use usePluginInfo hook for plugin data in TypeScript
Avoid deprecated components; check for JSDoc @deprecated tags, import paths containing /deprecated, and DEPRECATED_ file name prefixes
Use direct imports to specific files instead of barrel exports (index.ts) to avoid circular dependency cycles and improve build performance
Use import type for importing type...

Files:

  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (README.md)

Follow internationalization guidelines as documented in INTERNATIONALIZATION.md for all frontend code

Files:

  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (INTERNATIONALIZATION.md)

**/*.{ts,tsx,jsx}: The aria-label, aria-placeholder, aria-roledescription, and aria-valuetext attributes should be internationalized.
The optional i18nKey property on the react-i18next Trans component should only be used as a last resort when the parser incorrectly generates keys containing HTML tags.

Files:

  • frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx
🔇 Additional comments (1)
frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx (1)

165-174: LGTM!

Also applies to: 202-212

Comment on lines +83 to +93
const pvcNotFound = pvcResourceLoaded && !pvcResource;
const [scResource, scResourceLoaded, scResourceLoadError] = useK8sGet<StorageClassResourceKind>(
StorageClassModel,
pvcStorageClassName,
);

// Form is ready when either:
// - PVC was found and its StorageClass has loaded
// - PVC was not found (deleted) — annotations and snapshot status provide sufficient data
const formReady = pvcNotFound || (!!pvcStorageClassName && scResourceLoaded);

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate pvcNotFound on an explicit 404 signal.

Line 83 currently treats any “loaded but no PVC object” state as deleted. That can misclassify non-404 failures (RBAC/API/transient) as deletion and set formReady true incorrectly.

Suggested fix
-  const pvcNotFound = pvcResourceLoaded && !pvcResource;
+  const pvcNotFound = pvcResourceLoaded && !pvcResource && pvcResourceLoadError?.code === 404;

If this hook surfaces HTTP status via status instead of code, use that field instead.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const pvcNotFound = pvcResourceLoaded && !pvcResource;
const [scResource, scResourceLoaded, scResourceLoadError] = useK8sGet<StorageClassResourceKind>(
StorageClassModel,
pvcStorageClassName,
);
// Form is ready when either:
// - PVC was found and its StorageClass has loaded
// - PVC was not found (deleted) — annotations and snapshot status provide sufficient data
const formReady = pvcNotFound || (!!pvcStorageClassName && scResourceLoaded);
const pvcNotFound = pvcResourceLoaded && !pvcResource && pvcResourceLoadError?.code === 404;
const [scResource, scResourceLoaded, scResourceLoadError] = useK8sGet<StorageClassResourceKind>(
StorageClassModel,
pvcStorageClassName,
);
// Form is ready when either:
// - PVC was found and its StorageClass has loaded
// - PVC was not found (deleted) — annotations and snapshot status provide sufficient data
const formReady = pvcNotFound || (!!pvcStorageClassName && scResourceLoaded);
🤖 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
`@frontend/packages/console-app/src/components/modals/restore-pvc/restore-pvc-modal.tsx`
around lines 83 - 93, The code treats any "loaded but no PVC object"
(pvcNotFound computed from pvcResourceLoaded && !pvcResource) as deletion which
can misclassify non-404 errors; update the logic that computes pvcNotFound to
only be true when the GET hook indicates an explicit 404 (check the hook's error
payload field name, e.g., error.status or error.code) returned by the useK8sGet
call for the PVC (use the same variable holding the error/status), and then use
that gated pvcNotFound when deriving formReady so transient/API/RBAC errors
won't set formReady true.

@sg00dwin
Copy link
Copy Markdown
Member Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels May 14, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-59404, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @yapei

Details

In response to this:

/jira refresh

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.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 14, 2026

@openshift-ci-robot: GitHub didn't allow me to request PR reviews from the following users: yapei.

Note that only openshift members and repo collaborators can review this PR, and authors cannot review their own PRs.

Details

In response to this:

@sg00dwin: This pull request references Jira Issue OCPBUGS-59404, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @yapei

In response to this:

/jira refresh

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.

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 kubernetes-sigs/prow repository.

@logonoff
Copy link
Copy Markdown
Member

QA Verification Evidence

Details
Branch OCPBUGS-59404-volumesnapshot-restore
Baseline main @ c9d341853e
Candidate OCPBUGS-59404-volumesnapshot-restore @ 4b52d47963
Verified 2026-05-14
Browser Playwright 1.60.0 / Chrome for Testing 148.0.7778.96 (playwright chromium v1223)
OS Darwin 25.4.0
Jira OCPBUGS-59404

Verification Steps

# Route Action Status
1 /k8s/ns/.../VolumeSnapshot Navigate to VolumeSnapshot list ✅ pass
2 /k8s/ns/.../VolumeSnapshot/test-pvc-snapshot Navigate to detail page ✅ pass
3 (detail page) Actions > Restore as new PVC Open restore modal with PVC existing ✅ pass
4 (detail page) Actions > Restore as new PVC Open restore modal with PVC deleted ✅ pass
5 (modal) Click Restore button Restore PVC from snapshot (candidate only) ✅ pass
6 /k8s/ns/.../persistentvolumeclaims Navigate to PVC list ✅ pass
7 /k8s/cluster/storageclasses Navigate to StorageClasses ✅ pass
8 browser_console_messages Check for console errors ✅ pass
Animated overview (click to expand)
Baseline (main) Candidate (OCPBUGS-59404-volumesnapshot-restore)
Step 1: VolumeSnapshot list page (pass)
Baseline (main) Candidate (OCPBUGS-59404-volumesnapshot-restore)
Step 2: VolumeSnapshot detail page (pass)
Baseline (main) Candidate (OCPBUGS-59404-volumesnapshot-restore)
Step 3: Restore modal - PVC exists / regression check (pass)
Baseline (main) Candidate (OCPBUGS-59404-volumesnapshot-restore)

Both branches show identical behavior when the parent PVC exists: StorageClass=gp3-csi, Size=1 GiB, Restore button enabled.

⭐ Step 4: Restore modal - PVC deleted / bug fix (pass)

This is the key comparison. When the parent PVC is deleted:

  • Baseline (main): StorageClass dropdown and Size input are replaced with skeleton loaders. Restore button is disabled.
  • Candidate (PR): StorageClass dropdown shows all available storage classes with gp3-csi pre-selected. Size input shows 1 GiB. Restore button is enabled.
Baseline (main) - BROKEN Candidate (OCPBUGS-59404-volumesnapshot-restore) - FIXED
Step 5: Actual PVC restore - candidate only (pass)

On the candidate branch, clicking Restore successfully created a new PVC test-pvc-snapshot-restore:

Restored PVC detail page
Step 6-7: Storage overview pages (pass)
Page Baseline (main) Candidate (OCPBUGS-59404-volumesnapshot-restore)
PVC list
StorageClasses
Step 8: Console error check (pass)

Both branches show identical console errors — only expected 404s:

  • metal3.io/v1alpha1/provisionings/provisioning-configuration (metal3 not on cluster)
  • persistentvolumeclaims/test-pvc (expected — PVC was deliberately deleted)

No new console errors introduced by the fix.


Warning

This verification was performed by an AI agent. Results may contain false positives or miss
regressions that require human judgment. Always review the screenshots manually before approving.

Automated QA verification by Claude Code

Copy link
Copy Markdown
Member

@logonoff logonoff left a comment

Choose a reason for hiding this comment

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

/lgtm

@logonoff
Copy link
Copy Markdown
Member

/verified by claude

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 14, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 14, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: logonoff, sg00dwin

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:

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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 14, 2026
@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label May 14, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@logonoff: This PR has been marked as verified by claude.

Details

In response to this:

/verified by 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.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 14, 2026

@sg00dwin: all tests passed!

Full PR test history. Your PR dashboard.

Details

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 kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot openshift-merge-bot Bot merged commit fd28c3e into openshift:main May 14, 2026
8 checks passed
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: Jira Issue Verification Checks: Jira Issue OCPBUGS-59404
✔️ This pull request was pre-merge verified.
✔️ All associated pull requests have merged.
✔️ All associated, merged pull requests were pre-merge verified.

Jira Issue OCPBUGS-59404 has been moved to the MODIFIED state and will move to the VERIFIED state when the change is available in an accepted nightly payload. 🕓

Details

In response to this:

Analysis / Root cause:

The "Restore as new PVC" modal for VolumeSnapshots gates the StorageClass dropdown and Size input on pvcStorageClassName — a value derived exclusively from the parent PVC. When the parent PVC is deleted, useK8sGet returns a 404, pvcStorageClassName becomes undefined, and both fields permanently show skeleton loaders. The Restore button stays disabled because no storage class can be selected.

The snapshot already carries all necessary metadata via annotations (storage class, access modes, volume mode) set at creation time, plus status.restoreSize for the size — but the modal's rendering conditionals never fall through to use them.

Solution description:

Added two computed booleans to restore-pvc-modal.tsx:

  • pvcNotFound: detects when the PVC fetch completed with a 404
  • formReady: true when PVC is confirmed deleted OR when PVC and its StorageClass have loaded

Changed three rendering conditionals:

  1. StorageClass dropdown gate: !pvcStorageClassName || !scResourceLoaded!formReady
  2. When PVC is deleted, StorageClass dropdown shows all available storage classes (unfiltered) with the annotated value pre-selected
  3. Size input gate: !!pvcStorageClassName && scResourceLoadedformReady, with isInputDisabled skipping SC-based checks when PVC is not found

When the parent PVC exists, pvcNotFound=false and formReady reduces to the original condition — zero behavioral change.

Screenshots with fix:
Restore as new PVC form
New PVC details

Test setup:

A cluster with CSI snapshot support (e.g., AWS with gp3-csi and csi-aws-vsc). Adjust storageClassName and volumeSnapshotClassName for your environment.

# Create test namespace and PVC
oc create namespace snapshot-restore-test

oc apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: test-pvc
 namespace: snapshot-restore-test
spec:
 storageClassName: gp3-csi
 accessModes: [ReadWriteOnce]
 volumeMode: Filesystem
 resources:
   requests:
     storage: 1Gi
EOF

# PVC needs a consumer to bind (WaitForFirstConsumer)
oc apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
 name: test-pod
 namespace: snapshot-restore-test
spec:
 containers:
   - name: test
     image: registry.access.redhat.com/ubi9/ubi-minimal:latest
     command: ["sleep", "infinity"]
     volumeMounts:
       - name: data
         mountPath: /data
 volumes:
   - name: data
     persistentVolumeClaim:
       claimName: test-pvc
EOF

# Wait for PVC to bind
oc get pvc -n snapshot-restore-test -w
# Ctrl+C when STATUS = Bound

# Create snapshot
oc apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
 name: test-snapshot
 namespace: snapshot-restore-test
spec:
 volumeSnapshotClassName: csi-aws-vsc
 source:
   persistentVolumeClaimName: test-pvc
EOF

# Wait for snapshot to be ready
oc get volumesnapshot -n snapshot-restore-test -w
# Ctrl+C when READYTOUSE = true

Test cases:

  1. Regression check (PVC exists):
  • Go to Storage > VolumeSnapshots in project snapshot-restore-test
  • Kebab menu on test-snapshot > "Restore as new PVC"
  • Verify: StorageClass dropdown shows gp3-csi, Access mode and Volume mode selectors render, Size shows 1 GiB, Restore button is enabled
  • Cancel the modal
  1. Bug fix verification (PVC deleted):
oc delete pod test-pod -n snapshot-restore-test
oc delete pvc test-pvc -n snapshot-restore-test
  • Kebab menu on test-snapshot > "Restore as new PVC"
  • Verify: StorageClass dropdown renders with available storage classes (pre-selects gp3-csi), Access mode and Volume mode selectors render, Size shows 1 GiB, Restore button is enabled
  • Click Restore — a new PVC should be created successfully
  1. Cleanup:
oc delete namespace snapshot-restore-test

Summary by CodeRabbit

  • Bug Fixes
  • Enhanced the restore PVC modal to handle missing source PVCs. The form now displays all necessary controls and allows restoration to proceed using snapshot annotations and metadata, even when the original PVC no longer exists.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. component/core Related to console core functionality jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants