e75c8b37c8
Co-authored-by: nova28 <17953305+nova28@users.noreply.github.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
119 lines
4.6 KiB
Go
119 lines
4.6 KiB
Go
package runtime
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/kandev/kandev/internal/agent/runtime/lifecycle"
|
|
"github.com/kandev/kandev/internal/common/logger"
|
|
"github.com/kandev/kandev/internal/secrets"
|
|
)
|
|
|
|
// Standalone control-server ownership, exposed through the agent-runtime seam.
|
|
//
|
|
// The adoption handshake, its durable record, and the ownership renewer all
|
|
// live in runtime/lifecycle, but the caller that drives them at startup is the
|
|
// backend application package, which must not import lifecycle directly (see
|
|
// apps/backend/CLAUDE.md, "only internal/agent/runtime/ ... may import
|
|
// runtime/lifecycle"). These aliases and wrappers are that seam, in the same
|
|
// shape as SSHTaskDirReclaimer above: higher-level packages depend on this
|
|
// contract rather than on the lifecycle implementation.
|
|
|
|
// InheritedRecordScope reports what this launch found at the recorded control
|
|
// endpoint, which decides how an inherited executors_running row may be judged.
|
|
type InheritedRecordScope = lifecycle.InheritedRecordScope
|
|
|
|
const (
|
|
// InheritedRecordScopeNoServer means nothing answered, so no server holds
|
|
// the inherited rows and the process-identifier probe applies.
|
|
InheritedRecordScopeNoServer = lifecycle.InheritedRecordScopeNoServer
|
|
// InheritedRecordScopeForeignServer means a server answered but was not
|
|
// adopted, so its instances may still be alive on a server this backend
|
|
// does not drive.
|
|
InheritedRecordScopeForeignServer = lifecycle.InheritedRecordScopeForeignServer
|
|
// InheritedRecordScopeAdopted means this backend adopted the recorded
|
|
// server, so its enumeration is authoritative for inherited rows.
|
|
InheritedRecordScopeAdopted = lifecycle.InheritedRecordScopeAdopted
|
|
)
|
|
|
|
// AdoptionRecordStore is the narrow persistence contract the adoption
|
|
// orchestration reads and writes the installation-scoped record through.
|
|
type AdoptionRecordStore = lifecycle.AdoptionRecordStore
|
|
|
|
// AdoptionControlClient is the ownership surface adoption drives on a live
|
|
// control server.
|
|
type AdoptionControlClient = lifecycle.AdoptionControlClient
|
|
|
|
// AdoptionControlClientFactory builds a client targeting a recorded endpoint.
|
|
type AdoptionControlClientFactory = lifecycle.AdoptionControlClientFactory
|
|
|
|
// AdoptionOutcome is the result of attempting to adopt a detached server.
|
|
type AdoptionOutcome = lifecycle.AdoptionOutcome
|
|
|
|
// OwnershipRenewer keeps an adopted server's ownership lease renewed for as
|
|
// long as this backend drives it.
|
|
type OwnershipRenewer = lifecycle.OwnershipRenewer
|
|
|
|
// OwnershipClaimer is the single ownership-claim operation the renewer issues.
|
|
type OwnershipClaimer = lifecycle.OwnershipClaimer
|
|
|
|
// RequiredSurvivalCapabilities is the capability set this backend requires of
|
|
// a control server before adopting it.
|
|
var RequiredSurvivalCapabilities = lifecycle.RequiredSurvivalCapabilities
|
|
|
|
// AttemptAdoptControlServer runs the adoption handshake against the recorded
|
|
// control endpoint and reports whether this backend may drive that server.
|
|
func AttemptAdoptControlServer(
|
|
ctx context.Context,
|
|
store AdoptionRecordStore,
|
|
secretStore secrets.SecretStore,
|
|
newClient AdoptionControlClientFactory,
|
|
homeDir string,
|
|
requiredCapabilities []string,
|
|
recoveryReadTimeout time.Duration,
|
|
recoveryReadRetries int,
|
|
log *logger.Logger,
|
|
) AdoptionOutcome {
|
|
return lifecycle.AttemptAdoptControlServer(ctx, store, secretStore, newClient, homeDir,
|
|
requiredCapabilities, recoveryReadTimeout, recoveryReadRetries, log)
|
|
}
|
|
|
|
// ReclaimUnneededControlServer stops and clears a recorded server this launch
|
|
// will not adopt because the capability is disabled.
|
|
func ReclaimUnneededControlServer(
|
|
ctx context.Context,
|
|
store AdoptionRecordStore,
|
|
secretStore secrets.SecretStore,
|
|
newClient AdoptionControlClientFactory,
|
|
homeDir string,
|
|
recoveryReadTimeout time.Duration,
|
|
recoveryReadRetries int,
|
|
log *logger.Logger,
|
|
) {
|
|
lifecycle.ReclaimUnneededControlServer(ctx, store, secretStore, newClient, homeDir,
|
|
recoveryReadTimeout, recoveryReadRetries, log)
|
|
}
|
|
|
|
// RecordFreshControlServer persists the record and credential for a control
|
|
// server this backend just spawned, so a later launch can adopt it.
|
|
func RecordFreshControlServer(
|
|
ctx context.Context,
|
|
store AdoptionRecordStore,
|
|
secretStore secrets.SecretStore,
|
|
client AdoptionControlClient,
|
|
endpoint string,
|
|
credential string,
|
|
) error {
|
|
return lifecycle.RecordFreshControlServer(ctx, store, secretStore, client, endpoint, credential)
|
|
}
|
|
|
|
// NewOwnershipRenewer builds the renewer that holds an adopted server's
|
|
// ownership lease for this backend's lifetime.
|
|
func NewOwnershipRenewer(
|
|
claimer OwnershipClaimer,
|
|
interval time.Duration,
|
|
log *logger.Logger,
|
|
) *OwnershipRenewer {
|
|
return lifecycle.NewOwnershipRenewer(claimer, interval, log)
|
|
}
|