Files
pulse/internal/updates/updater.go
T
rcourtman 33d318a29e Delete the unreachable adapter Execute/Rollback update path and the unused UpdateQueue
The only production consumer of the UpdaterRegistry is the plan endpoint
(GET /api/updates/plan); every real apply runs through the in-Go pipeline
in manager.go ApplyUpdate, with concurrency held by updateMu/updateInFlight.
The InstallShAdapter Execute/Rollback path (install.sh piping, rollback
binary download, health wait) and the UpdateQueue were never called outside
tests, so fixes made there silently did nothing. Adapters are now plan
providers only: the Updater interface keeps SupportsApply, PrepareUpdate,
and GetDeploymentType, pinned by the new registry proof in
internal/api/updates_test.go.

The orphaned fetchAndVerifyReleaseSignature helper goes with it; its
fail-closed sidecar tests now exercise the manager's
downloadAndVerifyReleaseSignature directly. The deployment-installability
sshsig invariant now names the manager pipeline as the only surface that
fetches release artifacts, and api-contracts, storage-recovery, and
agent-lifecycle pin the same plan-provider-only shape at their update
transport boundaries. Stale adapter references in build-release.sh,
validate-release.sh, and the installtests comments are updated to match.
2026-07-10 01:14:40 +01:00

102 lines
3.1 KiB
Go

package updates
import (
"context"
"fmt"
)
// UpdateRequest represents a request to update
type UpdateRequest struct {
Version string
Channel string
Force bool
DryRun bool
}
// UpdatePlan contains information about how an update will be performed
type UpdatePlan struct {
CanAutoUpdate bool `json:"canAutoUpdate"`
Instructions []string `json:"instructions"`
Prerequisites []string `json:"prerequisites"`
EstimatedTime string `json:"estimatedTime,omitempty"`
RequiresRoot bool `json:"requiresRoot"`
RollbackSupport bool `json:"rollbackSupport"`
DownloadURL string `json:"downloadUrl,omitempty"`
Readiness *UpdateReadiness `json:"readiness,omitempty"`
}
// UpdateReadiness is the operator-facing preflight summary attached to an
// update plan. It is advisory unless a check is explicitly "blocked".
type UpdateReadiness struct {
Status string `json:"status"`
Summary string `json:"summary"`
Checks []UpdateReadinessCheck `json:"checks"`
}
// UpdateReadinessCheck is one concrete compatibility or continuity check for
// the requested server update.
type UpdateReadinessCheck struct {
ID string `json:"id"`
Status string `json:"status"`
Title string `json:"title"`
Summary string `json:"summary"`
Details []string `json:"details,omitempty"`
}
func EmptyUpdatePlan() UpdatePlan {
return UpdatePlan{}.NormalizeCollections()
}
func (p UpdatePlan) NormalizeCollections() UpdatePlan {
if p.Instructions == nil {
p.Instructions = []string{}
}
if p.Prerequisites == nil {
p.Prerequisites = []string{}
}
if p.Readiness != nil && p.Readiness.Checks == nil {
p.Readiness.Checks = []UpdateReadinessCheck{}
}
return p
}
// Updater describes how an update would be performed for a deployment type.
// Implementations are plan providers only; the actual apply runs through the
// in-Go pipeline in manager.go ApplyUpdate.
type Updater interface {
// SupportsApply returns true if this deployment type supports automated updates
SupportsApply() bool
// PrepareUpdate returns a plan describing how the update will be performed
PrepareUpdate(ctx context.Context, request UpdateRequest) (*UpdatePlan, error)
// GetDeploymentType returns the deployment type this updater handles
GetDeploymentType() string
}
// UpdaterRegistry manages updaters for different deployment types
type UpdaterRegistry struct {
updaters map[string]Updater
}
// NewUpdaterRegistry creates a new updater registry
func NewUpdaterRegistry() *UpdaterRegistry {
return &UpdaterRegistry{
updaters: make(map[string]Updater),
}
}
// Register registers an updater for a deployment type
func (r *UpdaterRegistry) Register(deploymentType string, updater Updater) {
r.updaters[deploymentType] = updater
}
// Get returns the updater for a deployment type
func (r *UpdaterRegistry) Get(deploymentType string) (Updater, error) {
updater, ok := r.updaters[deploymentType]
if !ok {
return nil, fmt.Errorf("no updater registered for deployment type: %s", deploymentType)
}
return updater, nil
}