Complete SCUM controlled deployment lifecycle

This commit is contained in:
npc0-hue
2026-07-25 10:13:53 +08:00
parent 6cfd929f7f
commit 15789e15b4
28 changed files with 1349 additions and 123 deletions
+41 -5
View File
@@ -25,6 +25,7 @@ func (svc *CoreService) CreateServerInstanceWorkflow(create domain.ServerLifecyc
if plugin.Status != domain.GamePluginStatusInstalled {
return domain.ServerLifecycleResult{}, validationError("plugin must be installed")
}
create.Deployment = applyPluginCreateDefaults(plugin, create.Deployment)
if err := validateLifecycleActionRef(plugin, domain.ServerLifecycleActionCreate); err != nil {
return domain.ServerLifecycleResult{}, err
}
@@ -32,6 +33,9 @@ func (svc *CoreService) CreateServerInstanceWorkflow(create domain.ServerLifecyc
if err := validator.ValidatePluginCreateInputs(plugin.CreateFields, create.Deployment.CreateInputs); err != nil {
return domain.ServerLifecycleResult{}, err
}
if err := validateScumDeploymentInputs(plugin, create.Deployment); err != nil {
return domain.ServerLifecycleResult{}, err
}
}
stamp := svc.now()
@@ -54,6 +58,15 @@ func (svc *CoreService) CreateServerInstanceWorkflow(create domain.ServerLifecyc
instance.Deployment.RuntimeBindings = domain.CopyStringMap(create.Bindings)
instance.Deployment.Revision = maxInt(1, instance.Deployment.Revision)
instance.Deployment.UpdatedAt = stamp
operation := "install"
if instance.Deployment.Mode == domain.ServerDeploymentModeExisting {
operation = "adopt"
}
if plan, planErr := scumDeploymentPlan(plugin, instance.Deployment, operation); planErr != nil {
return domain.ServerLifecycleResult{}, planErr
} else if plan != nil {
instance.DeploymentProjection = scumDeploymentProjection(plan, operation, stamp)
}
}
instance.ConfigContent = buildLogicalServerConfig(instance)
instance.ConfigChecksum = validator.BytesChecksum([]byte(instance.ConfigContent))
@@ -80,9 +93,20 @@ func (svc *CoreService) CreateServerInstanceWorkflow(create domain.ServerLifecyc
if err := svc.validateRunnableEndpoint(endpoint, domain.LifecycleCapabilityForAction(domain.ServerLifecycleActionCreate)); err != nil {
return domain.ServerLifecycleResult{}, err
}
if instance.DeploymentProjection.TemplateKey != "" {
instance.DeploymentProjection.State = "queued"
instance.DeploymentProjection.PreflightState = "queued"
instance.DeploymentProjection.UpdatedAt = stamp
}
if instance.Deployment.Mode != "" && !containsString(endpoint.Capabilities, domain.JobCapabilityDeploymentPlan) {
return domain.ServerLifecycleResult{}, validationError("run endpoint missing required capability: deployment.plan.v1")
}
if scumDeploymentCapabilityRequired(plugin, instance.Deployment) && !containsString(endpoint.Capabilities, domain.JobCapabilitySCUMDeploymentPlan) {
return domain.ServerLifecycleResult{}, validationError("run endpoint missing required capability: deployment.scum.v1")
}
if err := validateSCUMDeploymentTarget(plugin, instance.Deployment, endpoint); err != nil {
return domain.ServerLifecycleResult{}, err
}
if requiredShellCapability := deploymentShellCapability(instance.Deployment.Shell); requiredShellCapability != "" && !containsString(endpoint.Capabilities, requiredShellCapability) {
return domain.ServerLifecycleResult{}, validationError("run endpoint policy does not allow selected command shell")
}
@@ -284,6 +308,17 @@ func (svc *CoreService) dispatchLifecycleJob(instance domain.ServerInstance, act
return domain.Job{}, err
}
}
var serverDeploymentPlan *domain.ServerDeploymentPlan
if action == domain.ServerLifecycleActionCreate {
operation := "install"
if instance.Deployment.Mode == domain.ServerDeploymentModeExisting {
operation = "adopt"
}
serverDeploymentPlan, err = scumDeploymentPlan(plugin, instance.Deployment, operation)
if err != nil {
return domain.Job{}, err
}
}
job, err := svc.CreateJob(domain.Job{
ID: lifecycleJobID(instance.ID, action, idempotencyKey),
ServerInstanceID: instance.ID,
@@ -293,11 +328,12 @@ func (svc *CoreService) dispatchLifecycleJob(instance domain.ServerInstance, act
IdempotencyKey: idempotencyKey,
Progress: lifecycleJobProgress(instance.Deployment),
ExecutionInput: domain.JobExecutionInput{
WorkspaceScope: profileKey,
PluginID: plugin.ID,
LifecycleOperation: lifecycleExecutionOperation(action),
DLLExtensions: dllExtensions,
Deployment: deploymentPlanForDispatch(instance.Deployment),
WorkspaceScope: profileKey,
PluginID: plugin.ID,
LifecycleOperation: lifecycleExecutionOperation(action),
DLLExtensions: dllExtensions,
Deployment: deploymentPlanForDispatch(instance.Deployment),
ServerDeploymentPlan: serverDeploymentPlan,
},
})
if err != nil {