v0.80.0: PBS DR tier slice 2 — the apply-bridge (pbs_dr consumer, felhom-pbs-apply set-only wrapper, verify-pin-before-consume, adoption-first, loud consumed-failed, escrow seed)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Read-only query operations. All API-backed (Datastore.Audit / VM.Audit /
|
||||
@@ -108,6 +109,50 @@ func (c *Client) NodeStorage(ctx context.Context) ([]Storage, error) {
|
||||
return ss, c.get(ctx, "/nodes/"+c.node+"/storage", &ss)
|
||||
}
|
||||
|
||||
// StorageEntryConfig is the storage-entry CONFIG as served by GET /storage/{id} (PBS DR slice 2
|
||||
// adoption probe — the pbs-type fields the bridge compares against the descriptor). All fields
|
||||
// non-secret; the token secret lives in /etc/pve/priv/storage/<id>.pw, never in this response.
|
||||
type StorageEntryConfig struct {
|
||||
Storage string `json:"storage"`
|
||||
Type string `json:"type"`
|
||||
Server string `json:"server,omitempty"`
|
||||
Datastore string `json:"datastore,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Fingerprint string `json:"fingerprint,omitempty"`
|
||||
EncryptionKey string `json:"encryption-key,omitempty"` // K's OWN fingerprint (not the key)
|
||||
}
|
||||
|
||||
// StorageEntry returns GET /storage/{id} — the entry's configuration, or found=false when the id
|
||||
// does not exist (PVE answers HTTP 500 "does not exist" — mapped here so the adoption probe can
|
||||
// branch without string-matching upstream).
|
||||
func (c *Client) StorageEntry(ctx context.Context, id string) (*StorageEntryConfig, bool, error) {
|
||||
var e StorageEntryConfig
|
||||
err := c.get(ctx, "/storage/"+url.PathEscape(id), &e)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "does not exist") {
|
||||
return nil, false, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
return &e, true, nil
|
||||
}
|
||||
|
||||
// StorageActive returns whether GET /nodes/{node}/storage/{id}/status reports the entry active —
|
||||
// for a pbs entry that means PVE connected to the PBS with the stored credentials (the
|
||||
// post-apply/adoption health probe).
|
||||
func (c *Client) StorageActive(ctx context.Context, id string) (bool, error) {
|
||||
var st struct {
|
||||
Active int `json:"active"`
|
||||
Enabled int `json:"enabled"`
|
||||
}
|
||||
path := fmt.Sprintf("/nodes/%s/storage/%s/status", c.node, url.PathEscape(id))
|
||||
if err := c.get(ctx, path, &st); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return st.Active == 1, nil
|
||||
}
|
||||
|
||||
// StorageContent returns GET /nodes/{node}/storage/{store}/content (e.g. vzdump
|
||||
// archives + CT templates available for a restore).
|
||||
func (c *Client) StorageContent(ctx context.Context, store string) ([]StorageContent, error) {
|
||||
|
||||
Reference in New Issue
Block a user