Files
2026-03-25 11:11:37 +01:00

187 lines
4.6 KiB
Go

package utils
import (
"encoding/json"
"errors"
"sync"
"time"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/models/resources"
"cloud.o-forge.io/core/oc-lib/models/workflow"
"cloud.o-forge.io/core/oc-lib/tools"
)
type BookingResource struct {
ID string // resource MongoDB _id
PeerPID string // peer public PeerID (PID) — PlannerCache key
InstanceID string // resolved from WorkflowSchedule.SelectedInstances
}
// collectBookingResources returns unique storage and compute resources from the
// workflow graph. For each resource the selected instance ID is resolved from
// selectedInstances (the scheduler's SelectedInstances ConfigItem) so the planner
// check targets the exact instance chosen by the user.
func CollectBookingResources(wf *workflow.Workflow, selectedInstances workflow.ConfigItem) map[string]BookingResource {
if wf.Graph == nil {
return nil
}
seen := map[string]bool{}
result := map[string]BookingResource{}
// Resolve MongoDB peer _id (DID) → public PeerID (PID) used as PlannerCache key.
peerAccess := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
didToPID := map[string]string{}
resolvePID := func(did string) string {
if pid, ok := didToPID[did]; ok {
return pid
}
if data := peerAccess.LoadOne(did); data.Data != nil {
if p := data.ToPeer(); p != nil {
didToPID[did] = p.PeerID
return p.PeerID
}
}
return ""
}
resolveInstanceID := func(res interface {
GetID() string
GetCreatorID() string
}) string {
idx := selectedInstances.Get(res.GetID())
switch r := res.(type) {
case *resources.StorageResource:
if inst := r.GetSelectedInstance(idx); inst != nil {
return inst.GetID()
}
case *resources.ComputeResource:
if inst := r.GetSelectedInstance(idx); inst != nil {
return inst.GetID()
}
}
return ""
}
for _, item := range wf.GetGraphItems(wf.Graph.IsStorage) {
_, res := item.GetResource()
if res == nil {
continue
}
id := res.GetID()
if seen[id] {
continue
}
pid := resolvePID(res.GetCreatorID())
if pid == "" {
continue
}
seen[id] = true
result[pid] = BookingResource{
ID: id,
PeerPID: pid,
InstanceID: resolveInstanceID(res),
}
}
for _, item := range wf.GetGraphItems(wf.Graph.IsCompute) {
_, res := item.GetResource()
if res == nil {
continue
}
id := res.GetID()
if seen[id] {
continue
}
pid := resolvePID(res.GetCreatorID())
if pid == "" {
continue
}
seen[id] = true
result[pid] = BookingResource{
ID: id,
PeerPID: pid,
InstanceID: resolveInstanceID(res),
}
}
return result
}
// GetWorkflowPeerIDs loads the workflow and returns the deduplicated list of
// creator peer IDs for all its storage and compute resources.
// These are the peers whose planners must be watched by a check stream.
func GetWorkflowPeerIDs(wfID string, request *tools.APIRequest) ([]string, error) {
obj, code, err := workflow.NewAccessor(request).LoadOne(wfID)
if code != 200 || err != nil {
msg := "could not load workflow " + wfID
if err != nil {
msg += ": " + err.Error()
}
return nil, errors.New(msg)
}
wf := obj.(*workflow.Workflow)
if wf.Graph == nil {
return nil, nil
}
seen := map[string]bool{}
var peerIDs []string
for _, item := range wf.GetGraphItems(wf.Graph.IsStorage) {
_, res := item.GetResource()
if res == nil {
continue
}
if id := res.GetCreatorID(); id != "" && !seen[id] {
seen[id] = true
peerIDs = append(peerIDs, id)
}
}
for _, item := range wf.GetGraphItems(wf.Graph.IsCompute) {
_, res := item.GetResource()
if res == nil {
continue
}
if id := res.GetCreatorID(); id != "" && !seen[id] {
seen[id] = true
peerIDs = append(peerIDs, id)
}
}
realPeersID := []string{}
access := oclib.NewRequestAdmin(oclib.LibDataEnum(tools.PEER), nil)
for _, id := range peerIDs {
if data := access.LoadOne(id); data.Data != nil {
realPeersID = append(realPeersID, data.ToPeer().PeerID)
}
}
return realPeersID, nil
}
func FormatOptTime(t *time.Time) string {
if t == nil {
return "open"
}
return t.Format(time.RFC3339)
}
func Notify[T interface{}](mu *sync.RWMutex, registry map[string][]chan T, key string, toAdd T) {
mu.RLock()
subs := registry[key]
mu.RUnlock()
for _, ch := range subs {
select {
case ch <- toAdd:
default:
}
}
}
func Propalgate(peerID string, message tools.PropalgationMessage) {
b, _ := json.Marshal(message)
tools.NewNATSCaller().SetNATSPub(tools.PROPALGATION_EVENT, tools.NATSResponse{
FromApp: "oc-scheduler",
Datatype: -1,
Method: int(tools.PROPALGATION_EVENT),
Payload: b,
})
}