Declare SCUM Run data targets
This commit is contained in:
@@ -268,6 +268,11 @@ func runAutonomousLifecyclePlan(distribution domain.RunDistribution, instance do
|
||||
plan.LogSources = append(plan.LogSources, autonomousLogSource(source))
|
||||
}
|
||||
}
|
||||
for _, target := range plugin.RuntimeProfiles.DataTargets {
|
||||
if runtimePlatformsContain(target.Platforms, distribution.TargetOS) {
|
||||
plan.DataTargets = append(plan.DataTargets, autonomousDataTarget(target))
|
||||
}
|
||||
}
|
||||
if hasProfile && len(profile.DLLExtensionRefs) > 0 {
|
||||
endpoint := domain.RunEndpoint{ID: distribution.RunEndpointID, Platform: distribution.TargetOS, Architecture: distribution.TargetArch}
|
||||
extensions, err := lifecycleDLLExtensionPlans(plugin.RuntimeProfiles, profile, endpoint)
|
||||
@@ -326,6 +331,10 @@ func autonomousDLLExtension(extension domain.RuntimeDLLExtensionPlan) domain.Run
|
||||
return domain.RunAutonomousDLLExtension{Key: extension.Key, Version: extension.Version, ReleaseURL: extension.ReleaseURL, Checksum: extension.Checksum, SizeBytes: extension.SizeBytes, TargetKey: extension.TargetKey, ModKey: extension.ModKey, DLLRef: extension.DLLRef, SCUMExecutableChecksum: extension.SCUMExecutableChecksum, UE4SSABI: extension.UE4SSABI, RCONPort: extension.RCONPort}
|
||||
}
|
||||
|
||||
func autonomousDataTarget(target domain.RuntimeDataTarget) domain.RunAutonomousDataTarget {
|
||||
return domain.RunAutonomousDataTarget{Key: target.Key, Kind: target.Kind, TransportKey: target.TransportKey, SourceRootKey: target.SourceRootKey, SourcePath: target.SourcePath, WorkspaceKey: target.WorkspaceKey, RefreshPolicy: target.RefreshPolicy, MaxBytes: target.MaxBytes, Platforms: domain.CopyStringSlice(target.Platforms)}
|
||||
}
|
||||
|
||||
func autonomousDeploymentFromDefinition(definition domain.ServerDeploymentDefinition, profileKey string, bindings map[string]string) *domain.RunAutonomousDeployment {
|
||||
if definition.Mode == "" {
|
||||
return nil
|
||||
|
||||
@@ -45,6 +45,13 @@ func TestCoreServiceKeepsPlatformBuildKeyOffMachineJobChannel(t *testing.T) {
|
||||
domain.RuntimeLogSource{Key: "console", Kind: "process.stdout", TargetKey: "server/process", StreamKey: "console", CursorKind: "sequence", RetentionDays: 14},
|
||||
domain.RuntimeLogSource{Key: "server-events", Kind: "file.tail", TargetKey: "logs/server", StreamKey: "scum.server", CursorKind: "fingerprint", RetentionDays: 90},
|
||||
)
|
||||
plugin.RuntimeProfiles.TransportProfiles = append(plugin.RuntimeProfiles.TransportProfiles,
|
||||
domain.RuntimeTransportProfile{Key: "server-files", Kind: "file", TargetKey: "server-root", Capabilities: []string{domain.JobCapabilityRemoteRunFilesRead}},
|
||||
domain.RuntimeTransportProfile{Key: "world-db", Kind: "sqlite", TargetKey: "world-db", Capabilities: []string{domain.JobCapabilityRemoteRunDBSQLiteProbe}},
|
||||
)
|
||||
plugin.RuntimeProfiles.DataTargets = append(plugin.RuntimeProfiles.DataTargets,
|
||||
domain.RuntimeDataTarget{Key: "world-db", Kind: "sqlite.snapshot", TransportKey: "world-db", SourceRootKey: "server-root", SourcePath: "world/current.db", WorkspaceKey: "databases/world-db", RefreshPolicy: "on-demand-snapshot", MaxBytes: 128 * 1024 * 1024, Platforms: []string{"linux"}},
|
||||
)
|
||||
if err := svc.store.GamePlugins().Update(plugin); err != nil {
|
||||
t.Fatalf("seed plugin lifecycle assets: %v", err)
|
||||
}
|
||||
@@ -90,14 +97,14 @@ func TestCoreServiceKeepsPlatformBuildKeyOffMachineJobChannel(t *testing.T) {
|
||||
if plan == nil || plan.SchemaVersion != "1" || plan.ServerInstanceID != instance.ID || plan.PluginID != plugin.ID || plan.ProfileKey != "local" || plan.Bootstrap == nil || plan.Bootstrap.Action != domain.ServerLifecycleActionStart || plan.Bootstrap.TargetKey != "actions/start.json" {
|
||||
t.Fatalf("platform builder received incomplete autonomous lifecycle plan: %+v", plan)
|
||||
}
|
||||
if len(plan.DependencyProbes) != 1 || plan.DependencyProbes[0].Key != "java-runtime" || len(plan.InstallPlans) != 1 || plan.InstallPlans[0].Key != "java-install" || len(plan.LogSources) != 3 || !hasAutonomousLogSource(plan.LogSources, "process.stdout", "console") || !hasAutonomousLogSource(plan.LogSources, "file.tail", "latest-log") || !hasAutonomousLogSource(plan.LogSources, "file.tail", "scum.server") || plan.RuntimeBindings["logs/latest"] != "runtime.logs.latest" {
|
||||
if len(plan.DependencyProbes) != 1 || plan.DependencyProbes[0].Key != "java-runtime" || len(plan.InstallPlans) != 1 || plan.InstallPlans[0].Key != "java-install" || len(plan.LogSources) != 3 || !hasAutonomousLogSource(plan.LogSources, "process.stdout", "console") || !hasAutonomousLogSource(plan.LogSources, "file.tail", "latest-log") || !hasAutonomousLogSource(plan.LogSources, "file.tail", "scum.server") || len(plan.DataTargets) != 1 || plan.DataTargets[0].WorkspaceKey != "databases/world-db" || plan.DataTargets[0].SourcePath != "world/current.db" || plan.RuntimeBindings["logs/latest"] != "runtime.logs.latest" {
|
||||
t.Fatalf("autonomous lifecycle plan lost plugin runtime declarations: %+v", plan)
|
||||
}
|
||||
var seededPlan domain.RunAutonomousLifecyclePlan
|
||||
if err := json.Unmarshal([]byte(seedFiles[2].Content), &seededPlan); err != nil {
|
||||
t.Fatalf("unmarshal seeded autonomous lifecycle plan: %v", err)
|
||||
}
|
||||
if seededPlan.ServerInstanceID != plan.ServerInstanceID || seededPlan.Bootstrap == nil || seededPlan.Bootstrap.TargetKey != plan.Bootstrap.TargetKey {
|
||||
if seededPlan.ServerInstanceID != plan.ServerInstanceID || seededPlan.Bootstrap == nil || seededPlan.Bootstrap.TargetKey != plan.Bootstrap.TargetKey || len(seededPlan.DataTargets) != 1 || seededPlan.DataTargets[0].WorkspaceKey != "databases/world-db" {
|
||||
t.Fatalf("seeded lifecycle plan differs from build input: seed=%+v input=%+v", seededPlan, plan)
|
||||
}
|
||||
auth, err := svc.AuthenticateComponent(domain.ComponentAuthenticationRequest{
|
||||
|
||||
@@ -95,7 +95,11 @@ func TestSCUMSchemaProbeDispatchIsPlatformScheduledAndFenced(t *testing.T) {
|
||||
plugin.DeclaredPermissions = append(plugin.DeclaredPermissions, "server.remote.access")
|
||||
plugin.RequiredRunCapabilities = append(plugin.RequiredRunCapabilities, domain.JobCapabilityRemoteRunDBSQLiteProbe)
|
||||
plugin.RemoteAccess = domain.GamePluginRemoteAccess{Methods: []string{"run"}, RunCapabilities: []string{domain.JobCapabilityRemoteRunDBSQLiteProbe}, DatabaseEngines: []string{"sqlite"}}
|
||||
plugin.RuntimeProfiles.TransportProfiles = append(plugin.RuntimeProfiles.TransportProfiles, domain.RuntimeTransportProfile{Key: "scum-database", Kind: "sqlite", TargetKey: "scum-database", Capabilities: []string{domain.JobCapabilityRemoteRunDBSQLiteProbe}})
|
||||
plugin.RuntimeProfiles.TransportProfiles = append(plugin.RuntimeProfiles.TransportProfiles,
|
||||
domain.RuntimeTransportProfile{Key: "server-files", Kind: "file", TargetKey: "server-root", Capabilities: []string{domain.JobCapabilityRemoteRunFilesRead}},
|
||||
domain.RuntimeTransportProfile{Key: "scum-database", Kind: "sqlite", TargetKey: "scum-database", Capabilities: []string{domain.JobCapabilityRemoteRunDBSQLiteProbe}},
|
||||
)
|
||||
plugin.RuntimeProfiles.DataTargets = append(plugin.RuntimeProfiles.DataTargets, domain.RuntimeDataTarget{Key: "scum-database", Kind: "sqlite.snapshot", TransportKey: "scum-database", SourceRootKey: "server-root", SourcePath: "SCUM/Saved/SaveFiles/SCUM.db", WorkspaceKey: "databases/scum-database", RefreshPolicy: "on-demand-snapshot", MaxBytes: 1024 * 1024 * 1024, Platforms: []string{"windows"}})
|
||||
plugin.RuntimeProfiles.LifecycleProfiles[0].TransportKeys = append(plugin.RuntimeProfiles.LifecycleProfiles[0].TransportKeys, "scum-database")
|
||||
plugin.SCUMLiveData = domain.SCUMLiveDataManifest{SchemaVersion: "1", Probe: domain.SCUMSchemaProbeDeclaration{Capability: domain.JobCapabilityRemoteRunDBSQLiteProbe, TargetKey: "scum-database", Bounds: domain.DefaultSCUMSchemaProbeBounds()}, CapabilityGates: []domain.SCUMLiveDataCapabilityGateDeclaration{{Capability: domain.SCUMDataCapabilitySchemaProbe, Gate: domain.SCUMCapabilityGateDisabled, AdapterVersion: "scum-live-data-v0", EvidenceStatus: domain.SCUMCapabilityEvidenceMissing, SafeReason: "waiting for current service evidence"}}}
|
||||
if err := svc.store.GamePlugins().Update(plugin); err != nil {
|
||||
|
||||
@@ -28,6 +28,9 @@ func (svc *CoreService) RequestSCUMSchemaProbeForSession(sessionID, serverInstan
|
||||
if plugin.SCUMLiveData.SchemaVersion == "" || probe.Capability != domain.JobCapabilityRemoteRunDBSQLiteProbe || strings.TrimSpace(probe.TargetKey) == "" {
|
||||
return domain.SCUMSchemaProbeRequest{}, domain.RemoteAdapterResult{}, validationError("SCUM schema probe is not declared by the plugin")
|
||||
}
|
||||
if !scumSchemaProbeHasDataTarget(plugin.RuntimeProfiles, probe.TargetKey) {
|
||||
return domain.SCUMSchemaProbeRequest{}, domain.RemoteAdapterResult{}, validationError("SCUM schema probe target is not declared as a generated Run data target")
|
||||
}
|
||||
endpoint, err := svc.store.RunEndpoints().Get(instance.RunEndpointID)
|
||||
if err != nil {
|
||||
return domain.SCUMSchemaProbeRequest{}, domain.RemoteAdapterResult{}, err
|
||||
@@ -94,6 +97,16 @@ func scumSchemaProbeDatabaseIdentity(targetKey string) string {
|
||||
return strings.TrimPrefix(trimmed, "databases/")
|
||||
}
|
||||
|
||||
func scumSchemaProbeHasDataTarget(profiles domain.GamePluginRuntimeProfiles, targetKey string) bool {
|
||||
expectedWorkspaceKey := "databases/" + scumSchemaProbeDatabaseIdentity(targetKey)
|
||||
for _, target := range profiles.DataTargets {
|
||||
if target.Key == targetKey && target.Kind == "sqlite.snapshot" && target.WorkspaceKey == expectedWorkspaceKey && target.RefreshPolicy == "on-demand-snapshot" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func scumSchemaProbeAdapterVersion(manifest domain.SCUMLiveDataManifest) string {
|
||||
for _, gate := range manifest.CapabilityGates {
|
||||
if gate.Capability == domain.SCUMDataCapabilitySchemaProbe {
|
||||
|
||||
Reference in New Issue
Block a user