feat: 完整游戏运维功能
This commit is contained in:
@@ -36,9 +36,13 @@ func (svc *CoreService) CreateServerInstanceWorkflow(create domain.ServerLifecyc
|
||||
OwnerUserID: create.OwnerUserID,
|
||||
State: domain.ServerInstanceStateInstalling,
|
||||
ConfigVersion: 1,
|
||||
ConfigKey: "server.properties",
|
||||
CreatedAt: stamp,
|
||||
UpdatedAt: stamp,
|
||||
}
|
||||
instance.ConfigContent = buildLogicalServerConfig(instance)
|
||||
instance.ConfigChecksum = validator.BytesChecksum([]byte(instance.ConfigContent))
|
||||
instance.ConfigUpdatedAt = stamp
|
||||
if err := validator.ValidateServerInstance(instance); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
@@ -51,9 +55,16 @@ func (svc *CoreService) CreateServerInstanceWorkflow(create domain.ServerLifecyc
|
||||
if err := svc.validateLifecycleIdempotency(instance.RunEndpointID, create.IdempotencyKey, instance.ID, domain.LifecycleCapabilityForAction(domain.ServerLifecycleActionCreate)); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
binding, err := svc.buildRuntimeBinding(instance, plugin, domain.RuntimeBindingUpdate{ProfileKey: create.ProfileKey, Bindings: create.Bindings}, true)
|
||||
if err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
if err := svc.store.ServerInstances().Create(instance); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
if err := svc.store.RuntimeBindings().Create(binding); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
|
||||
job, err := svc.dispatchLifecycleJob(instance, domain.ServerLifecycleActionCreate, create.IdempotencyKey)
|
||||
if err != nil {
|
||||
@@ -108,6 +119,18 @@ func (svc *CoreService) StopServerInstanceForSession(sessionID string, command d
|
||||
return svc.StopServerInstance(command)
|
||||
}
|
||||
|
||||
func (svc *CoreService) QueryServerInstanceProcessForSession(sessionID string, command domain.ServerLifecycleCommand) (domain.ServerLifecycleResult, error) {
|
||||
if err := svc.authorizeServerLifecycle(sessionID, command.ServerInstanceID); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
return svc.dispatchExistingServerLifecycle(command, domain.ServerLifecycleActionStatus, []domain.ServerInstanceState{
|
||||
domain.ServerInstanceStateReady,
|
||||
domain.ServerInstanceStateStopped,
|
||||
domain.ServerInstanceStateRunning,
|
||||
domain.ServerInstanceStateFailed,
|
||||
})
|
||||
}
|
||||
|
||||
func (svc *CoreService) dispatchExistingServerLifecycle(command domain.ServerLifecycleCommand, action domain.ServerLifecycleAction, allowedStates []domain.ServerInstanceState) (domain.ServerLifecycleResult, error) {
|
||||
command = domain.CopyServerLifecycleCommand(command)
|
||||
if err := validator.ValidateServerLifecycleCommand(command); err != nil {
|
||||
@@ -138,6 +161,9 @@ func (svc *CoreService) dispatchExistingServerLifecycle(command domain.ServerLif
|
||||
if err := validator.ValidateServerInstanceDependencies(instance, plugin, endpoint); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
if err := svc.requireCompleteRuntimeBindings(instance.OwnerUserID, instance.ID, "server.lifecycle."+string(action)+".denied"); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
if err := validateRunnableEndpoint(endpoint, domain.LifecycleCapabilityForAction(action)); err != nil {
|
||||
return domain.ServerLifecycleResult{}, err
|
||||
}
|
||||
@@ -168,12 +194,33 @@ func (svc *CoreService) lifecycleDependencies(pluginID string, runEndpointID str
|
||||
|
||||
func (svc *CoreService) dispatchLifecycleJob(instance domain.ServerInstance, action domain.ServerLifecycleAction, idempotencyKey string) (domain.Job, error) {
|
||||
capability := domain.LifecycleCapabilityForAction(action)
|
||||
binding, err := svc.runtimeBindingForServer(instance.ID)
|
||||
if err != nil {
|
||||
return domain.Job{}, err
|
||||
}
|
||||
plugin, err := svc.store.GamePlugins().Get(instance.PluginID)
|
||||
if err != nil {
|
||||
return domain.Job{}, err
|
||||
}
|
||||
actionRef := binding.ProfileKey
|
||||
if profile, ok := runtimeLifecycleProfileForKey(plugin.RuntimeProfiles, binding.ProfileKey); ok {
|
||||
if ref := runtimeProfileActionRef(profile.ActionRefs, action); ref != "" {
|
||||
actionRef = ref
|
||||
}
|
||||
} else if ref := lifecycleActionRef(plugin, action); ref != "" {
|
||||
actionRef = ref
|
||||
}
|
||||
if strings.TrimSpace(actionRef) == "" {
|
||||
return domain.Job{}, validationError(fmt.Sprintf("plugin %s lifecycle action is required", action))
|
||||
}
|
||||
job, err := svc.CreateJob(domain.Job{
|
||||
ID: lifecycleJobID(instance.ID, action, idempotencyKey),
|
||||
ServerInstanceID: instance.ID,
|
||||
RunEndpointID: instance.RunEndpointID,
|
||||
Capability: capability,
|
||||
TargetKey: actionRef,
|
||||
IdempotencyKey: idempotencyKey,
|
||||
ExecutionInput: domain.JobExecutionInput{WorkspaceScope: binding.ProfileKey},
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Job{}, err
|
||||
@@ -184,6 +231,30 @@ func (svc *CoreService) dispatchLifecycleJob(instance domain.ServerInstance, act
|
||||
return job, nil
|
||||
}
|
||||
|
||||
func runtimeProfileActionRef(actions domain.PluginLifecycleActions, action domain.ServerLifecycleAction) string {
|
||||
switch action {
|
||||
case domain.ServerLifecycleActionCreate:
|
||||
return actions.Install
|
||||
case domain.ServerLifecycleActionStart:
|
||||
return actions.Start
|
||||
case domain.ServerLifecycleActionStop:
|
||||
return actions.Stop
|
||||
case domain.ServerLifecycleActionStatus:
|
||||
return actions.Status
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func runtimeLifecycleProfileForKey(profiles domain.GamePluginRuntimeProfiles, key string) (domain.RuntimeLifecycleProfile, bool) {
|
||||
for _, profile := range profiles.LifecycleProfiles {
|
||||
if profile.Key == key {
|
||||
return profile, true
|
||||
}
|
||||
}
|
||||
return domain.RuntimeLifecycleProfile{}, false
|
||||
}
|
||||
|
||||
func (svc *CoreService) validateLifecycleIdempotency(runEndpointID string, idempotencyKey string, serverInstanceID string, capability string) error {
|
||||
existing, err := svc.store.Jobs().GetByIdempotency(runEndpointID, idempotencyKey)
|
||||
if errors.Is(err, repo.ErrNotFound) {
|
||||
@@ -213,6 +284,8 @@ func lifecycleActionRef(plugin domain.GamePlugin, action domain.ServerLifecycleA
|
||||
return plugin.LifecycleActions.Start
|
||||
case domain.ServerLifecycleActionStop:
|
||||
return plugin.LifecycleActions.Stop
|
||||
case domain.ServerLifecycleActionStatus:
|
||||
return plugin.LifecycleActions.Status
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user