CI / test (push) Successful in 5m24s
The judges' machine was selected by the judge's profile, but any other model could still be placed beside it. A node labelled llmgw.role now takes only profiles whose selector asks for that role. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
108 lines
3.4 KiB
Go
108 lines
3.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/control/placement"
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/onboard"
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/settings"
|
|
)
|
|
|
|
// Machines of the judges' own. Under load on a 4-core control plane that was
|
|
// also a node, 38 of 60 requests were refused for want of a judgment; with the
|
|
// judges on a node of their own the same test refused 2. A judge machine is
|
|
// added as a node carrying judgeRoleLabel, and the judge's profile selects
|
|
// that label, so nothing else is placed beside it and it on nothing else.
|
|
|
|
// judgeRoleLabel marks a node as the judges'.
|
|
const (
|
|
judgeRoleLabel = placement.RoleLabel
|
|
judgeRoleValue = "judge"
|
|
)
|
|
|
|
// judgeMachine is a machine for the judges: user@host, and the connection the
|
|
// setup screen already made to it, when it made one.
|
|
type judgeMachine struct {
|
|
target string
|
|
remote onboard.Remote
|
|
}
|
|
|
|
// ensureJudgeNodes adds each judge machine as a node labelled for the
|
|
// judges, and says how many cores the smallest of them has.
|
|
func (in *serverInit) ensureJudgeNodes(ctx context.Context) error {
|
|
if len(in.judgeMachines) == 0 {
|
|
return nil
|
|
}
|
|
na := nodeAdd{serverCfg: in.configPath(), plain: true}
|
|
na.opts.PKI = in.pkiDir
|
|
na.opts.NoFirewall = in.noFirewall
|
|
if err := na.prepare(); err != nil {
|
|
return err
|
|
}
|
|
in.judgeCPUs = nil
|
|
for _, jm := range in.judgeMachines {
|
|
o := na.target(jm.target)
|
|
fmt.Fprintf(in.out, " .. adding %s as a node for the judges\n", o.Addr)
|
|
r := onboard.New(o, nil)
|
|
if jm.remote != nil {
|
|
r.Remote = jm.remote
|
|
}
|
|
res, err := r.Run(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("%s: %w", o.Addr, err)
|
|
}
|
|
if err := na.watch(ctx, res.Node, func(onboard.Event) {}); err != nil && err != errNoAdmin {
|
|
return fmt.Errorf("%s: %w", res.Node, err)
|
|
}
|
|
if out, err := r.Remote.Run(ctx, "nproc", nil); err == nil {
|
|
if n, err := strconv.Atoi(strings.TrimSpace(string(out))); err == nil {
|
|
in.judgeCPUs = append(in.judgeCPUs, n)
|
|
}
|
|
}
|
|
if _, err := changeStoredSettings(in.configPath(), "a node for the judges, from init", func(doc *settings.Doc) error {
|
|
return doc.SetYAML([]string{"agents", "nodes", res.Node, "labels", judgeRoleLabel}, judgeRoleValue)
|
|
}); err != nil {
|
|
return fmt.Errorf("labelling %s for the judges: %w", res.Node, err)
|
|
}
|
|
in.done("%s is a node for the judges alone (%s: %s)", res.Node, judgeRoleLabel, judgeRoleValue)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// judgePlacement is the judge's cores and where it may run: on the judge
|
|
// machines when there are some, by init's rule over their cores; otherwise
|
|
// on any node, with this machine's plan.
|
|
func (in *serverInit) judgePlacement() (cores int, selector map[string]string) {
|
|
if len(in.judgeMachines) == 0 {
|
|
return in.cpuPlan().judge, nil
|
|
}
|
|
return refitCores(in.judgeFor().Replicas, in.judgeCPUs), map[string]string{judgeRoleLabel: judgeRoleValue}
|
|
}
|
|
|
|
// judgeMachineFlag is --judge-node, given again for each machine.
|
|
type judgeMachineFlag struct{ to *[]judgeMachine }
|
|
|
|
func (f judgeMachineFlag) String() string {
|
|
if f.to == nil {
|
|
return ""
|
|
}
|
|
var out []string
|
|
for _, m := range *f.to {
|
|
out = append(out, m.target)
|
|
}
|
|
return strings.Join(out, ",")
|
|
}
|
|
|
|
func (f judgeMachineFlag) Set(v string) error {
|
|
if strings.TrimSpace(v) == "" {
|
|
return fmt.Errorf("--judge-node wants user@host")
|
|
}
|
|
*f.to = append(*f.to, judgeMachine{target: strings.TrimSpace(v)})
|
|
return nil
|
|
}
|
|
|
|
func (judgeMachineFlag) Type() string { return "user@host" }
|