Files
browser/platform/service/server_lifecycle_projection.go
T

152 lines
5.8 KiB
Go

package service
import (
"strings"
"time"
"browser.local/platform/domain"
"browser.local/platform/validator"
)
func (svc *CoreService) projectRemoteAdapterJobResult(job domain.Job, stamp time.Time) error {
if !strings.HasPrefix(job.Capability, "remote.") || job.ServerInstanceID == "" || !isTerminalJobState(job.State) {
return nil
}
result := domain.AuditResultSuccess
if job.State == domain.JobStateFailed || job.State == domain.JobStateCancelled {
result = domain.AuditResultFailed
}
summary := "remote adapter " + job.Capability + " completed with bounded result reference"
if job.State == domain.JobStateFailed {
summary = "remote adapter " + job.Capability + " failed or timed out; retry/fencing remained platform-owned"
}
if job.State == domain.JobStateCancelled {
summary = "remote adapter " + job.Capability + " was cancelled before terminal projection"
}
return svc.recordAuditEvent("run:"+job.RunEndpointID, "remote-adapter.result", "server-instance", job.ServerInstanceID, result, summary)
}
func (svc *CoreService) projectLifecycleJobResult(job domain.Job, stamp time.Time) error {
if job.Capability == domain.JobCapabilityConfigWrite {
if job.State != domain.JobStateSucceeded {
return svc.recordAuditEvent("run:"+job.RunEndpointID, "config.write.result", "server-instance", job.ServerInstanceID, domain.AuditResultFailed, job.ExecutionResult.AuditSummary)
}
instance, err := svc.store.ServerInstances().Get(job.ServerInstanceID)
if err != nil {
return err
}
instance.ConfigKey = job.TargetKey
instance.ConfigContent = job.ExecutionInput.Content
instance.ConfigChecksum = job.ExecutionResult.Checksum
instance.ConfigVersion = job.ExecutionResult.Version
instance.ConfigUpdatedAt = stamp
instance.UpdatedAt = stamp
if err := validator.ValidateServerInstance(instance); err != nil {
return err
}
if err := svc.store.ServerInstances().Update(instance); err != nil {
return err
}
return svc.recordAuditEvent("run:"+job.RunEndpointID, "config.write.result", "server-instance", instance.ID, domain.AuditResultSuccess, job.ExecutionResult.AuditSummary)
}
nextState, ok := lifecycleProjectedState(job.Capability, job.State)
if !ok || job.ServerInstanceID == "" {
return nil
}
instance, err := svc.store.ServerInstances().Get(job.ServerInstanceID)
if err != nil {
return err
}
if plan := job.ExecutionInput.ServerDeploymentPlan; plan != nil {
projection := domain.CopyServerDeploymentProjection(instance.DeploymentProjection)
projection.Operation = plan.Operation
projection.TemplateKey = plan.TemplateKey
projection.TemplateVersion = plan.TemplateVersion
projection.UpdatedAt = stamp
if evidence := job.ExecutionResult.ServerDeploymentEvidence; evidence != nil {
projection.State = "verified"
projection.PreflightState = evidence.PreflightState
projection.DiscoveryState = evidence.DiscoveryState
projection.MappingState = evidence.MappingState
projection.VerificationState = evidence.VerificationState
projection.DiscoveredFacts = domain.CopyStringMap(evidence.DiscoveredFacts)
projection.MappingResults = domain.CopyStringMap(evidence.MappingResults)
projection.VerificationResults = domain.CopyStringMap(evidence.VerificationResults)
projection.FailureCode = evidence.FailureCode
}
if job.State == domain.JobStateFailed || job.State == domain.JobStateCancelled {
projection.State = "failed"
if projection.FailureCode == "" && job.State == domain.JobStateCancelled {
projection.FailureCode = "cancelled"
}
}
instance.DeploymentProjection = projection
}
instance.State = nextState
instance.UpdatedAt = stamp
if err := validator.ValidateServerInstance(instance); err != nil {
return err
}
if err := svc.store.ServerInstances().Update(instance); err != nil {
return err
}
auditResult := domain.AuditResultSuccess
if job.State == domain.JobStateFailed || job.State == domain.JobStateCancelled {
auditResult = domain.AuditResultFailed
}
return svc.recordAuditEvent("run:"+job.RunEndpointID, "lifecycle.result", "server-instance", instance.ID, auditResult, job.Progress.Message)
}
func (svc *CoreService) projectServerDeploymentProgress(job domain.Job, stamp time.Time) error {
plan := job.ExecutionInput.ServerDeploymentPlan
if plan == nil || job.ServerInstanceID == "" {
return nil
}
instance, err := svc.store.ServerInstances().Get(job.ServerInstanceID)
if err != nil {
return err
}
projection := domain.CopyServerDeploymentProjection(instance.DeploymentProjection)
projection.State = "running"
projection.Operation = plan.Operation
projection.TemplateKey = plan.TemplateKey
projection.TemplateVersion = plan.TemplateVersion
switch job.Progress.Phase {
case "preflight":
projection.PreflightState = "running"
case "scan", "discover", "discovery":
projection.DiscoveryState = "running"
case "install", "configure", "mapping":
projection.MappingState = "running"
case "start", "health":
projection.VerificationState = "running"
}
projection.UpdatedAt = stamp
instance.DeploymentProjection = projection
instance.UpdatedAt = stamp
return svc.store.ServerInstances().Update(instance)
}
func lifecycleProjectedState(capability string, jobState domain.JobState) (domain.ServerInstanceState, bool) {
if capability != domain.LifecycleCapabilityInstall && capability != domain.LifecycleCapabilityStart && capability != domain.LifecycleCapabilityStop {
return "", false
}
if jobState == domain.JobStateFailed || jobState == domain.JobStateCancelled {
return domain.ServerInstanceStateFailed, true
}
if jobState != domain.JobStateSucceeded {
return "", false
}
switch capability {
case domain.LifecycleCapabilityInstall:
return domain.ServerInstanceStateReady, true
case domain.LifecycleCapabilityStart:
return domain.ServerInstanceStateRunning, true
case domain.LifecycleCapabilityStop:
return domain.ServerInstanceStateStopped, true
default:
return "", false
}
}