Documentation
¶
Overview ¶
Package aggapi is a thin client for the state-snapshotter aggregated subresource API exposed through the kube-apiserver aggregation layer.
After C9 there is no whole-subtree server-side aggregation: each snapshot node exposes three per-CR subresources, addressed by the node's resource plural:
- manifests-download: the node's own captured manifests (status preserved, namespace made relative). Served by the node's OWN subresource group (core group for the core Snapshot, the domain-prefixed group for domain snapshot CRs — the domain apiserver proxies to the core content layer); CSI VolumeSnapshot leaves use the dedicated VS-connector group instead.
- manifests-with-data-restoration: a ready-to-apply manifest array for the node's whole subtree (the server delegates domain subtrees internally). Served by the node's OWN subresource group (core group for the core Snapshot, the domain-prefixed group for domain snapshot CRs).
- manifests-and-children-refs-upload: import one node's manifests plus its direct child refs. Served by the node's OWN subresource group (core group for the core Snapshot, the domain-prefixed group for domain snapshot CRs — the domain apiserver's upload facade records the node's own childrenSnapshotRefs and forwards the manifests to the core content layer); CSI VolumeSnapshot leaves use the dedicated VS-connector group instead. The upload is bind-first: it returns 409 ImportContentNotBound until the node's SnapshotContent is bound.
All three subresources now route the same way — by the node's own group — so there is no longer any download/upload group asymmetry. Every subresource is addressed by the node's own namespaced CR (Snapshot, domain snapshot CR, or CSI VolumeSnapshot leaf). The client never reads cluster-scoped SnapshotContent objects.
Index ¶
- Constants
- Variables
- type Client
- func (c *Client) LeafDataExportTarget(ref NodeRef) (string, string, string, error)
- func (c *Client) NodeManifestsDownload(ctx context.Context, ref NodeRef) ([]byte, error)
- func (c *Client) RestoreManifests(ctx context.Context, ref NodeRef, targetNamespace string) ([]byte, error)
- func (c *Client) RestoreManifestsScoped(ctx context.Context, ref NodeRef, targetNamespace string, ...) ([]byte, error)
- func (c *Client) UploadManifests(ctx context.Context, ref NodeRef, body []byte) ([]byte, error)
- type NodeRef
- type RestoreScope
- type RestoreScopeOptions
Constants ¶
const ( // CoreSubresourcesGroup is the core controller's aggregated subresources API group. // It serves manifests-download for every node kind and the core Snapshot's // restore/upload subresources. CoreSubresourcesGroup = "subresources.state-snapshotter.deckhouse.io" // CoreSubresourcesVersion is the version served under CoreSubresourcesGroup. CoreSubresourcesVersion = "v1alpha1" // DomainSubresourcesGroupPrefix is prepended to a domain snapshot's API group to // address its aggregated subresources group (e.g. "sds-unified-snapshots-poc.deckhouse.io" // -> "subresources.sds-unified-snapshots-poc.deckhouse.io"). DomainSubresourcesGroupPrefix = "subresources." // VSConnectorGroup is the generic-PVC extended VolumeSnapshot connector subresource group. VSConnectorGroup = "subresources.snapshot.storage.k8s.io" // VSConnectorVersion is the version served under VSConnectorGroup. VSConnectorVersion = "v1" // StorageGroup is the API group of the core Snapshot / SnapshotContent CRDs. StorageGroup = "state-snapshotter.deckhouse.io" // VolumeSnapshotGroup is the CSI external-snapshotter API group of VolumeSnapshot leaves. VolumeSnapshotGroup = "snapshot.storage.k8s.io" // VolumeSnapshotResource is the resource plural of CSI VolumeSnapshot objects. VolumeSnapshotResource = "volumesnapshots" // VolumeSnapshotKind is the kind of CSI VolumeSnapshot leaf nodes. VolumeSnapshotKind = "VolumeSnapshot" )
Aggregated subresource API groups and versions.
const ( // SubManifestsDownload reads one node's own captured manifests. SubManifestsDownload = "manifests-download" // SubManifestsRestore reads a ready-to-apply manifest array for a node's subtree. SubManifestsRestore = "manifests-with-data-restoration" // SubManifestsUpload imports one node's manifests plus its direct child refs. SubManifestsUpload = "manifests-and-children-refs-upload" )
Subresource names.
const ( // DefaultMaxResponseBytes caps one aggregated-API response at 64 MiB. Manifest // bundles may be large, but must not grow client memory without a finite bound. DefaultMaxResponseBytes int64 = 64 << 20 )
const ReasonImportContentNotBound = "ImportContentNotBound"
ReasonImportContentNotBound is the canonical status.reason of the bind-first 409 the namespaced (core / domain / VS-connector) manifests-and-children-refs-upload returns while a node's status.boundSnapshotContentName is still empty. It mirrors state-snapshotter usecase.ReasonImportContentNotBound verbatim — the wire contract d8 retries on until the binder binds the node's SnapshotContent.
Variables ¶
var ErrResponseTooLarge = errors.New("aggregated API response exceeds byte limit")
ErrResponseTooLarge reports that an aggregated-API response exceeded its byte budget.
var ErrRestoreBadRequest = errors.New("restore request rejected as invalid")
ErrRestoreBadRequest is returned by RestoreManifestsScoped when the server rejects the request as invalid (state-snapshotter restore.ErrBadRequest wire equivalent: an unknown scope value, an object filter missing kind or name, or an object filter used with a scope other than RestoreScopeNode). Distinguish it from other failures with errors.Is.
var ErrRestoreNotFound = errors.New("restore target not found")
ErrRestoreNotFound is returned by RestoreManifestsScoped when the addressed node, or — with an object filter — the requested object within it, does not exist. Distinguish it from other failures with errors.Is.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client performs aggregated-apiserver calls over an absolute-path REST interface (typically a discovery REST client) and resolves a node's GVK to its resource plural via a RESTMapper.
func NewClient ¶
func NewClient(restClient rest.Interface, mapper meta.RESTMapper) *Client
NewClient builds a Client from a raw REST interface (e.g. the discovery REST client) and a RESTMapper used to resolve GVK -> resource plural.
func NewClientForConfig ¶
NewClientForConfig builds a Client from a rest.Config, constructing the discovery REST client internally. mapper resolves GVK -> resource plural.
func (*Client) LeafDataExportTarget ¶
LeafDataExportTarget resolves the DataExport targetRef {group, resource, kind} for a snapshot leaf node. CSI VolumeSnapshot leaves use the fixed constants VolumeSnapshotGroup / VolumeSnapshotResource / VolumeSnapshotKind; all other kinds derive group from the leaf's apiVersion, use its own kind directly, and resolve the resource plural via the RESTMapper.
This is used to build a DataExport that the storage-volume-data-manager controller can route through its kind-agnostic snapshot export path (categorySnapshot): group/kind must identify a namespaced snapshot CR so the controller can read its status.boundSnapshotContentName → SnapshotContent → status.dataRef.
TEMP REVERTME: resource (plural) is populated in addition to kind so the DataExport satisfies the deployed storage-volume-data-manager (mr135) GVR-based CRD, which requires spec.targetRef.resource. The kind-based contract is not yet in SVDM main. Sending both resource and kind is safe because each CRD prunes the field it doesn't know.
func (*Client) NodeManifestsDownload ¶
NodeManifestsDownload performs GET <node>/manifests-download and returns the raw JSON array body (the node's own captured manifests).
The call is retried with bounded exponential backoff on a transient aggregated-API error (see isTransientManifestsDownloadError) — observed in practice as the aggregated APIService backend briefly restarting/overloading and returning "the server is currently unable to handle the request" (HTTP 503).
func (*Client) RestoreManifests ¶
func (c *Client) RestoreManifests(ctx context.Context, ref NodeRef, targetNamespace string) ([]byte, error)
RestoreManifests performs GET <node>/manifests-with-data-restoration?targetNamespace=<ns> and returns the raw apply-ready JSON array body for the node's whole subtree.
It is a thin wrapper over RestoreManifestsScoped with a zero-value RestoreScopeOptions; callers that need scope=node or an object filter call RestoreManifestsScoped directly.
func (*Client) RestoreManifestsScoped ¶
func (c *Client) RestoreManifestsScoped(ctx context.Context, ref NodeRef, targetNamespace string, opts RestoreScopeOptions) ([]byte, error)
RestoreManifestsScoped performs GET <node>/manifests-with-data-restoration with targetNamespace and, when set, the server's scope/kind/name/apiVersion query params (restore_handler.go parseRestoreQueryOptions). Each of opts.Scope/FilterKind/FilterName/FilterAPIVersion is sent ONLY when non-empty — an empty Scope omits the scope param entirely rather than sending scope=subtree explicitly, reproducing the server's own default byte-for-byte.
func (*Client) UploadManifests ¶
UploadManifests performs POST <node>/manifests-and-children-refs-upload with the given JSON body ({"manifests": <array>, "childRefs": [...]}) and returns the raw body.
The upload is bind-first: the aggregated apiserver refuses it with 409 ImportContentNotBound until the addressed node's status.boundSnapshotContentName is set. The import orchestrator (see snapimport.Run) already gates the whole upload pass behind a collective wait-for-bind, so this per-request retry is only a safety net for the narrow read-after-write race where the CLI observed a node bound but this upload endpoint has not yet — see postManifestsUpload.
type NodeRef ¶
NodeRef uniquely identifies a snapshot node for aggregated subresource calls. It is intentionally string-based (no typed objects) so that domain-specific kinds can be addressed without registering their Go types.
func (NodeRef) IsVolumeSnapshotLeaf ¶
IsVolumeSnapshotLeaf reports whether the ref addresses a CSI VolumeSnapshot leaf, which is served by the VS-connector subresource group instead of the core group.
type RestoreScope ¶
type RestoreScope string
RestoreScope selects the compilation depth of a RestoreManifestsScoped call, mirroring state-snapshotter's usecase/restore.Scope wire values verbatim (restore_handler.go parseRestoreQueryOptions) — these literals go on the wire as the "scope" query param, so they must match the server exactly, not just read similarly.
const ( // RestoreScopeSubtree compiles the addressed node and its whole subtree, recursively. It is // the server's default when the scope query param is omitted entirely. RestoreScopeSubtree RestoreScope = "subtree" // RestoreScopeNode compiles ONLY the addressed node, with no descendants. Required before an // object filter (FilterKind/FilterName/FilterAPIVersion) is accepted. RestoreScopeNode RestoreScope = "node" )
type RestoreScopeOptions ¶
type RestoreScopeOptions struct {
Scope RestoreScope
FilterKind string
FilterName string
FilterAPIVersion string
}
RestoreScopeOptions narrows a RestoreManifestsScoped call to one node (Scope == RestoreScopeNode) and, optionally, a single captured object within that node (FilterKind + FilterName, with FilterAPIVersion further disambiguating). The server accepts the object filter ONLY together with Scope == RestoreScopeNode and rejects any other combination with a 400 (restore_handler.go parseRestoreQueryOptions) — RestoreManifestsScoped does not pre-validate this client-side, it lets the server enforce its own contract and surfaces the resulting ErrRestoreBadRequest. A zero-value RestoreScopeOptions reproduces today's default (full subtree, no filter) byte-for-byte: no scope/kind/name/apiVersion query params are sent at all.