Skip to content

[dataprotection] Add Cosmos DB item-level recovery - #10486

Open
Shashank Singh (Shashank1306s) wants to merge 5 commits into
Azure:mainfrom
Shashank1306s:feature/cosmosdb-item-level-recovery
Open

Shashank Singh (Shashank1306s) wants to merge 5 commits into
Azure:mainfrom
Shashank1306s:feature/cosmosdb-item-level-recovery

Conversation

@Shashank1306s

@Shashank1306s Shashank Singh (Shashank1306s) commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

🤖 PR Validation — ️✔️ All clear

Breaking Changes
️✔️ None

Related commands

az dataprotection backup-instance initialize-restoreconfig --datasource-type AzureCosmosDB

az dataprotection backup-instance restore initialize-for-item-recovery --datasource-type AzureCosmosDB

Summary

Adds AzureCosmosDB item-level (database/container) restore, following the existing AzureElasticSAN pattern:

  • Enable item-level recovery in the AzureCosmosDB manifest.
  • initialize-restoreconfig --datasource-type AzureCosmosDB --resource-identifiers ... returns GenericRestoreDatasourceCriteria with ResourceListSelectionCriteria; identifiers are passed through unchanged. --resource-identifiers is required, as for AzureElasticSAN.
  • restore initialize-for-item-recovery --datasource-type AzureCosmosDB --restore-configuration ... uses that configuration as the restore criteria. --restore-configuration is required, as for AzureElasticSAN.
  • Help examples, a README script section, HISTORY and version 1.14.0.

No client-side limits, naming rules or target-type checks are added; the selection and target are validated by the service (validate-for-restore). Identity, MSI permission and restore transport handling are reused unchanged.

Other datasources' logic is unchanged. helpers.py only gains a file-level # pylint: disable=chained-comparison because CI lints the whole module and flags pre-existing Blob prefix-range lines; the Blob code is identical to main.

Validation

  • CI (this head, 4ebb7cca): all checks pass, including azdev style/linter, the breaking change test and integration tests on Python 3.10-3.14.
  • Offline: Cosmos test module (+2 tests) and the 11-module replay regression set: 87 passed, 24 existing skips, 0 failed (network blocked).
  • Live, this head (ECY / eastus2euap, locally built wheel): item-level restore of a single container (db1/col1) from a VaultStore recovery point into an empty account restored only that container; its documents match the recovery point exactly, and the unselected containers and databases were not restored.
  • Live, earlier head (East Asia): 7 restores completed with data verification - full account, single container, single database, mixed containers + database, multiple containers, multiple databases (system-assigned identity) and single container with a user-assigned identity. See the live-results comment. The requests generated by this head are JSON-identical to those (13/13).

General Guidelines

  • Extension version follows schema
  • Upstream style/linter/integration checks pass on this head
  • Live item-level restore cases completed with data verification

@microsoft-github-policy-service microsoft-github-policy-service Bot added the customer-reported Issues that are reported by GitHub users external to the Azure organization. label Oct 19, 2026
@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

Thank you for your contribution Shashank Singh (@Shashank1306s)! We will review the pull request and get back to you soon.

@yonzhan

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@Shashank1306s

Copy link
Copy Markdown
Contributor Author

Final validation update (commit 3230471)

Upstream azdev-style, azdev-linter, release-version calculation/output and CLA checks are now successful. Credential Scan and Policy Check are successful too. The remaining Azure integration/build checks are still pending/unknown; the PR remains draft.

Addressed the initial missing-final-newline finding and two pre-existing chained-comparison warnings. The latter change is behavior-equivalent: the actual old/new Blob prefix validators returned identical acceptance/errors across 225 range combinations.

Revalidated the published code:

  • Source: 840 tests + 131 subtests passed.
  • Rebuilt/private-installed final wheel: 840 + 131 passed with source discovery disabled.
  • Existing completed regression selection: 85 passed, 24 existing skips.
  • Standard local index checks: 7 passed, 2 CI-only skips.
  • Clean local worktree; final branch pushed without force.

Live native CLI restore/data-exclusion acceptance is still not executed: exact fresh-target/RBAC/cost authorization was not supplied. No live resource/role/data/vault-setting writes were performed. Four old recorded modules still have the same bounded-timeout outcome on both untouched upstream and this branch; no full-suite-green claim is made.

@Shashank1306s

Copy link
Copy Markdown
Contributor Author

Real-data wheel acceptance: all seven cases passed

Tested the local dataprotection 1.14.0 wheel, built from current PR head bc67e9b, against the existing real-data NoSQL fixture in East Asia. Isolated wheel import/discovery and SHA256 were verified; no source shadowing.

Native restore scenario DBs / containers / documents Result
Full-account, SAMI 3 / 7 / 14 Completed + exact data verified
Single container, SAMI 1 / 1 / 2 Completed + exact data verified
Whole database, SAMI 1 / 2 / 4 Completed + exact data verified
Mixed containers/database, SAMI 2 / 4 / 8 Completed + exact data verified
Multiple containers, SAMI 1 / 2 / 4 Completed + exact data verified
Multiple databases, SAMI 2 / 6 / 12 Completed + exact data verified
Attached UAMI 1 / 1 / 2 Completed + exact data verified

Every lifecycle step used native az dataprotection: config -> full/item initialization -> MSI permissions -> validation -> one restore trigger -> specific job show. All seven jobs were independently re-queried as Completed, with the correct backup instance and Restore operation/category.

Verified exact selected inventory, partition keys, document IDs/values/nested objects/array order and exclusions against the frozen recovery point. Post-backup data was excluded. Source remained unchanged (3 DBs / 8 containers / 15 documents). Completed 2026-10-19 12:25 UTC.

Only fresh tagged targets and narrow target/verification roles were created. No source, existing vault/policy/retention/network/identity changes or cleanup. Targets remain billable. Detailed evidence stays local, not added to the product diff.

Scope: seven positive NoSQL full/ILR cases in one region. No new backup/protection lifecycle or live negative/50-selector/other-region/API certification is claimed. This supersedes earlier comments saying live acceptance was pending.

@Shashank1306s
Shashank Singh (Shashank1306s) marked this pull request as ready for review October 19, 2026 15:43
Copilot AI balanced review requested due to automatic review settings October 19, 2026 15:43

Copilot AI left a comment

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.

🔵 Needs a closer look

The data-recovery workflow needs human sign-off and confirmation of pending upstream validation for the current revision.

No open issues 🎉

What changed in this PR

Adds Cosmos DB for NoSQL database/container recovery to the existing dataprotection restore workflow, reusing shared identity, permission, and transport handling.

Changes:

  • Enables item-level recovery with validated selectors and alternate-account targets.
  • Adds focused configuration, request, and validation tests.
  • Documents recovery workflows and bumps the extension to 1.14.0.
File Description
src/​dataprotection/​setup.py Bumps version to 1.14.0.
src/​dataprotection/​README.md Documents Cosmos recovery and identity usage.
src/​dataprotection/​HISTORY.rst Records the new recovery capability.
src/​dataprotection/​azext_dataprotection/​tests/​latest/​test_dataprotection_cosmosdb.py Tests selectors, configuration, requests, and validation.
src/​dataprotection/​azext_dataprotection/​manual/​Manifests/​AzureCosmosDB.py Enables item-level recovery.
src/​dataprotection/​azext_dataprotection/​manual/​helpers.py Validates Cosmos selections and constructs restore criteria.
src/​dataprotection/​azext_dataprotection/​manual/​custom.py Integrates Cosmos configuration and target checks.
src/​dataprotection/​azext_dataprotection/​manual/​_params.py Updates restore argument descriptions.
src/​dataprotection/​azext_dataprotection/​manual/​_help.py Adds Cosmos command guidance and examples.

Review effort: Balanced

…ing the AzureElasticSAN pattern

- Remove client-side checks not backed by the service or live ILR testing: selector count cap, character/duplicate/overlap rules, strict restore-configuration schema checks and target ARM-type checks.

- initialize-restoreconfig and get_resource_criteria_list now mirror AzureElasticSAN: require --resource-identifiers / --restore-configuration and pass them through.

- Revert shared-path changes: Cosmos rejection in initialize-for-data-recovery, unsupported-datasource error text, and the Blob prefix-range comparison (byte-identical to main; pre-existing chained-comparison lint suppressed at file level).

- Generic help, README and HISTORY wording; tests cover the live-validated request shape and the required inputs only.
"resource_selectors": resource_selectors
}

if datasource_type == "AzureCosmosDB":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[Suggestion] For AzureCosmosDB, --resource-name-overrides and the AKS-only arguments are silently ignored, and identifiers are passed through without stripping. Please reject unsupported arguments and empty or whitespace identifiers, as the AzureElasticSAN branch does, so an input like db1/ fails early instead of at validate-for-restore.

restore_criteria_list.append(restore_criteria)
return restore_criteria_list

if datasource_type == "AzureCosmosDB":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[Suggestion] --container-list, --from/--to-prefix-pattern and --vaulted-blob-prefix-pattern are silently ignored here, and any restore_configuration is accepted, including an AKS criteria object. For parity with Az.DataProtection, please reject those arguments and require object_type == 'GenericRestoreDatasourceCriteria'.

@@ -319,7 +319,8 @@ def load_arguments(self, _):
help='Key value mapping for resource modifier reference')
c.argument('resource_identifiers', type=str, nargs='+',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[Nit] The first sentence still reads "List of source volume identifiers". Consider making it datasource-neutral, for example "List of resource identifiers to restore", and keeping the per-datasource details after it.

# pylint: disable=unnecessary-list-index-lookup
# pylint: disable=unidiomatic-typecheck
# pylint: disable=possibly-used-before-assignment
# pylint: disable=chained-comparison

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[Nit] Consider scoping chained-comparison to the existing Blob prefix lines with inline # pylint: disable= rather than disabling it for the whole module, so new code is still checked.

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

Labels

act-codegen-extensibility-squad Auto-Assign Auto assign by bot CosmosDB customer-reported Issues that are reported by GitHub users external to the Azure organization. Data Protection

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants