Make generated run lifecycle autonomous
This commit is contained in:
@@ -111,12 +111,6 @@ func (svc *CoreService) RegisterRunHello(hello domain.RunControlHello) (domain.R
|
||||
return domain.RunControlHelloResult{}, err
|
||||
}
|
||||
svc.runSessions[hello.RunEndpointID] = session
|
||||
if err := svc.queueManagedGuidedDeploymentAfterRegistration(hello); err != nil {
|
||||
return domain.RunControlHelloResult{}, err
|
||||
}
|
||||
if err := svc.queueRuntimeStateReconciliationAfterRegistration(hello, generation); err != nil {
|
||||
return domain.RunControlHelloResult{}, err
|
||||
}
|
||||
featureFlags := []string{"control.hello", "control.heartbeat", "signed-envelope.v1.optional"}
|
||||
if session.RequireSignedRequests {
|
||||
featureFlags[2] = "signed-envelope.v1.required"
|
||||
@@ -132,96 +126,6 @@ func (svc *CoreService) RegisterRunHello(hello domain.RunControlHello) (domain.R
|
||||
}), nil
|
||||
}
|
||||
|
||||
// queueRuntimeStateReconciliationAfterRegistration lets a generated Run correct
|
||||
// stale observed state after reconnecting. Platform still owns command dispatch,
|
||||
// but the Run-owned process supervisor is authoritative for whether the local
|
||||
// managed process exists.
|
||||
func (svc *CoreService) queueRuntimeStateReconciliationAfterRegistration(hello domain.RunControlHello, generation int) error {
|
||||
if hello.ComponentKind != domain.DistributionComponentRun || strings.TrimSpace(hello.ServerInstanceID) == "" {
|
||||
return nil
|
||||
}
|
||||
instance, err := svc.store.ServerInstances().Get(hello.ServerInstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if instance.RunEndpointID != hello.RunEndpointID || instance.RunEndpointID != dedicatedRunEndpointID(instance.ID) {
|
||||
return nil
|
||||
}
|
||||
if instance.State != domain.ServerInstanceStateRunning && instance.State != domain.ServerInstanceStateFailed {
|
||||
return nil
|
||||
}
|
||||
if !containsString(hello.CapabilityReport.Capabilities, domain.LifecycleCapabilityStatus) {
|
||||
return nil
|
||||
}
|
||||
active, err := svc.hasActiveServerLifecycleJob(instance.ID)
|
||||
if err != nil || active {
|
||||
return err
|
||||
}
|
||||
plugin, endpoint, err := svc.lifecycleDependencies(instance.PluginID, instance.RunEndpointID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateLifecycleActionRef(plugin, domain.ServerLifecycleActionStatus); err != nil {
|
||||
return nil
|
||||
}
|
||||
if err := validateServerInstanceLifecycleDependencies(instance, plugin, endpoint, domain.ServerLifecycleActionStatus); err != nil {
|
||||
return nil
|
||||
}
|
||||
if err := svc.validateRunnableEndpoint(endpoint, domain.LifecycleCapabilityStatus); err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = svc.dispatchLifecycleJob(instance, domain.ServerLifecycleActionStatus, fmt.Sprintf("runtime-state-reconcile:%s:g%d", instance.ID, generation))
|
||||
return err
|
||||
}
|
||||
|
||||
func (svc *CoreService) hasActiveServerLifecycleJob(serverInstanceID string) (bool, error) {
|
||||
jobs, err := svc.store.Jobs().List(domain.JobFilter{ServerInstanceID: serverInstanceID})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, job := range jobs {
|
||||
if !isLifecycleJobCapability(job.Capability) {
|
||||
continue
|
||||
}
|
||||
if job.State == domain.JobStateQueued || job.State == domain.JobStateAccepted || job.State == domain.JobStateRunning || job.State == domain.JobStateRetrying {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func isLifecycleJobCapability(capability string) bool {
|
||||
switch capability {
|
||||
case domain.LifecycleCapabilityInstall, domain.LifecycleCapabilityStart, domain.LifecycleCapabilityStop, domain.LifecycleCapabilityStatus:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// queueManagedGuidedDeploymentAfterRegistration advances only a newly-created,
|
||||
// dedicated guided server. Selecting guided-install is the owner's prior
|
||||
// authorization for the plugin-declared bootstrap action; reconnects remain
|
||||
// idempotent.
|
||||
func (svc *CoreService) queueManagedGuidedDeploymentAfterRegistration(hello domain.RunControlHello) error {
|
||||
if hello.ComponentKind != domain.DistributionComponentRun || strings.TrimSpace(hello.ServerInstanceID) == "" {
|
||||
return nil
|
||||
}
|
||||
instance, err := svc.store.ServerInstances().Get(hello.ServerInstanceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if instance.RunEndpointID != hello.RunEndpointID || instance.RunEndpointID != dedicatedRunEndpointID(instance.ID) || instance.State != domain.ServerInstanceStateDraft || instance.Deployment.Mode != domain.ServerDeploymentModeGuided {
|
||||
return nil
|
||||
}
|
||||
_, err = svc.deployServerInstance(domain.ServerLifecycleCommand{
|
||||
ServerInstanceID: instance.ID,
|
||||
ExpectedConfigVersion: instance.ConfigVersion,
|
||||
IdempotencyKey: fmt.Sprintf("managed-deploy:%s:r%d", instance.ID, instance.Deployment.Revision),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (svc *CoreService) validateDedicatedRunHello(hello domain.RunControlHello) error {
|
||||
if hello.ComponentKind != domain.DistributionComponentRun {
|
||||
return validationError("component-authenticated run hello must use the run component")
|
||||
|
||||
Reference in New Issue
Block a user