synology_apm_repo.sdk.api.catalog module¶
Catalog/Frame: one catalog’s own workload/version/provider
operations, part of the Repository Layer (the Session/Repository/
Catalog split CLI/TUI code imports directly; everything below it is an
implementation detail this package hides). Catalog is obtained from
Repository.catalogs()/Repository.catalog_by_id() (the sibling
api.repository module); the two modules meet at Repository.resolve()’s
canonical/human-ref dispatch, which api.repository itself owns.
- class synology_apm_repo.sdk.api.catalog.Frame(level, catalog=None, workload=None, version=None, provider=None, node=None)¶
Bases:
objectWhere a human ref’s segments landed after
Repository.walk_human_ref— exactly as deep as they went, no deeper.levelsays which of the fields below (if any) is meaningful; the others are carried along for breadcrumb rendering and for continuing the walk one level further. Resolving a version always continues straight into its node tree (at leastprovider.root()), solevelis never"version"on its own — a version and itsprovideronly ever appear together withlevel="node".- provider: UnitProvider | None = None¶
- class synology_apm_repo.sdk.api.catalog.Catalog(dedup_repo, connection, *, saas_streams, track, require_key_verified)¶
Bases:
objectOne catalog within an opened
Repository: a singledb/ connection_configrow (connection) plus the workload/version/ provider operations scoped to it. Never constructed directly.For a vault, several sibling
Catalog``s share one underlying ``DedupRepo(one physical dedup pool) — this mirrors one openedPool/dbset queried for severalconnection_configrows. For object storage, eachCatalogowns its own independently-openedDedupRepo— a distinct physical pool per sibling repo-id (FORMAT-SPEC.md: no cross-repo-id dedup).saas_streamsis shared, not owned: it’s theRepository-levelSaasStreamCachebuilt against this samededup_repo(seeapi.repository._OpenCatalog), borrowed by every SaaS provider this catalog hands out viaprovider()rather than each opening its own.A provider this hands out is tracked by the owning
Repository—Repository.close()closes it, not this object;Catalogitself has noclose().- property catalog_id: CatalogId¶
The shared repo-id/connection-config-id fallback formula (also used by
units.node_ref.canonical_ref_for, so both call sites derive the same id):self._dedup_repo.layout.repo_id(this catalog’s own repo-id, set on everyRepoLayoutcatalog_repo_layouts()derives forOBJECT_STORE) is used when available, falling back tostr(connection_config_id)for a vault (whoseRepoLayout.repo_idis alwaysNone) and for the one object-storage edge case with no derivable repo-id (seestorage.layout’s_data_dir_ancestor) — safe there too, since that case only arises when this is the sole catalog reachable from itsRepositoryanyway.
- property info: RepoInfo¶
This catalog’s own
repo_info— genuinely per-catalog for object storage (each repo-id has its own marker file), and the vault-wide one shared by every sibling for a vault.
- async workloads()¶
Raises
KeyRequiredError/KeyMismatchErrorbefore any I/O if the owning repository is encrypted and not yet key-verified — seeRepository._require_key_verified. Without this, a locked repository’s workload list would otherwise come back silently empty or wrong, indistinguishable from “this catalog genuinely has no workloads”.
- async versions(workload, *, include_deleted=False)¶
The raw catalog read (newest-first by real backup time, ties broken by
version_iddescending) — nothing is filtered out. A version whose content later turns out unresolvable (a genuine gap, or routine backend-side generation rotation the resolving Unit already absorbs — seeunits.saas.stream) raises when actually opened (VM/FS, GW/M365) or surfaces a diagnostic node in place of the missing disk (PC/PS — seeunits.device_pcps), the same asverify()already treats it; this method never hides a real catalog row in advance of that. Same key gate asworkloads().
- async provider(version, *, object_db_id=None, force_raw=False)¶
Dispatches
versionto the rightUnitProviderbytarget_type/Workload.sub_type, degrading toRawObjectProviderwhen nothing recognizes it.
- async verify(level=VerifyLevel.QUICK, *, progress=None)¶
Integrity check over this catalog’s own
DedupRepo— for a vault, where several siblingCatalog``s share one ``DedupRepo, this is the same check as every sibling’s ownverify(), not one scoped to this catalog’s own rows alone (the top-down walk checks the shared pool via every catalog’s own workloads/versions, not one connection’s data alone). Same key gate asworkloads()/versions().
- async walk_human_ref(segments, *, object_db_id=None)¶
The three levels below a chosen catalog — workload -> version -> item — raising
NotFoundErrorthe moment a segment doesn’t match.segmentsis never empty here:Repository.walk_human_ref(this method’s only caller) already returns its own"catalog"Framedirectly once a human ref names nothing past the catalog itself.