openvibers/openvibe.link Commits

v0.37.1: a pairing in another --home leaves the node service alone (#98)

OP OpenVibers committed 11 days ago · 09eefe5666 · 3 files, +44 −3

The service has one name on a machine (openvibe-node) whatever --home it runs, and pair restarted it whenever it
was running. So pairing a test node in its own folder beside a working robot's service restarted that robot's node
(found 11-02 answering the community LOOI team, who keep a v0.14 Cozmo setup beside their test node). Now only the
default home's pairing restarts it; a pairing with --home says the service was left alone and how to restart it
if it runs that home. TestPairInAnotherHomeLeavesTheServiceAlone stubs the service manager.

Changes

ddiff --git a/STATUS.json b/STATUS.json
iindex 0082c85..f1bcebc 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -5,7 +5,7 @@
"wave": "T15",
"plan": "Plan track T15 (Bot complete) and ADR-043 (Bot: devices, pairing, control and safety); the computer plugin and the job worker serve OpenVibe.Actor and the Codes job runner (tracks T14/T17)",
"kind": "client",
-- "version": "0.37.0",
++ "version": "0.37.1",
"release": "v0.36.0: the ai plugin (0.2.0) passes tools to the machine's own model server and hands back the calls the model asked for, never running one, so an agent on OpenVibe (Actor) can work on a model this machine serves; its capabilities say tools: true (contracts 0.277.0). v0.35.0: the Node applies the roles the network's machines hub gives it at each check-in (codes.worker starts the job worker it was installed with, desks.host and ai.host are checked against what the machine was installed for, an unknown role is ignored, and the local configuration always wins), and its status reports them back; a desk's first browser start in a cold sandbox gets 90 s. v0.34.0: on Windows a killed plugin takes every process it started with it (a Job Object with kill-on-close), as the process group does on Linux and macOS, so a bridge helper cannot keep a robot's link open after the Node stops or restarts its plugin; the Node reads what the coding tools remember (read-only, local, redacted) and `openvibe-node memory` uploads it to your own store; the heartbeat carries the machine's fleet of coding agents; the Codes job runner pin is v0.5.2",
"runtime": "go 1.24 (one static binary per platform); plugins in Python 3; an ESP32 Arduino library",
"database": "none",
ddiff --git a/cmd/openvibe-node/main.go b/cmd/openvibe-node/main.go
iindex a946191..3429ad3 100644
---- a/cmd/openvibe-node/main.go
++++ b/cmd/openvibe-node/main.go
@@@ -353,13 +353,28 @@ func finishPair(g *globals, a pairArgs, cfg *config.Config, noConfig bool, stdou
}
chownLikeDir(g.paths.ConfigFile(), g.paths.ConfigDir)
}
-- if service.Status(serviceOptions(g, "")) == "running" {
-- _ = service.Control(serviceOptions(g, ""), "restart")
++ // The service has one name on a machine (service.Name) whatever --home it runs, so a pairing in another --home
++ // (a second node, a test node) must not restart it: that would restart a different node (11-02: a test node
++ // paired in its own folder beside a working robot's service). Only the default home's pairing restarts it.
++ if g.home != "" {
++ if serviceStatus(serviceOptions(g, "")) == "running" {
++ fmt.Fprintln(stdout, "A node service is running on this machine; it was left alone. If it runs this --home, restart it (Windows: `sc stop openvibe-node` then `sc start openvibe-node`; Linux: `sudo systemctl restart openvibe-node`).")
++ }
++ return nil
++ }
++ if serviceStatus(serviceOptions(g, "")) == "running" {
++ _ = serviceControl(serviceOptions(g, ""), "restart")
fmt.Fprintln(stdout, "The service was running and has been restarted with the new credential.")
}
return nil
}
++// The service manager, behind seams so the pairing tests can watch it (service.Status and service.Control otherwise).
++var (
++ serviceStatus = service.Status
++ serviceControl = service.Control
++)
++
func cmdPair(g *globals, a pairArgs, stdout io.Writer) error {
code, err := link.NormalizeCode(a.code)
if err != nil {
ddiff --git a/cmd/openvibe-node/main_test.go b/cmd/openvibe-node/main_test.go
iindex 34f964a..c19712e 100644
---- a/cmd/openvibe-node/main_test.go
++++ b/cmd/openvibe-node/main_test.go
@@@ -18,6 +18,7 @@ import (
"github.com/OpenVibers/OpenVibe.Node/internal/fakebot"
"github.com/OpenVibers/OpenVibe.Node/internal/protocol"
"github.com/OpenVibers/OpenVibe.Node/internal/safety"
++ "github.com/OpenVibers/OpenVibe.Node/internal/service"
"github.com/OpenVibers/OpenVibe.Node/internal/video"
)
@@@ -302,3 +303,28 @@ func TestRunDryRun(t *testing.T) {
t.Fatalf("no shutdown stop in logs:\n%s", logs.String())
}
}
++
++// A pairing in its own --home never restarts the machine's node service: the service has one name whatever home it runs,
++// so it may be another node's (11-02: a test node paired in its own folder beside a working robot's service).
++func TestPairInAnotherHomeLeavesTheServiceAlone(t *testing.T) {
++ srv := fakebot.New()
++ defer srv.Close()
++ srv.AddCode("WXYZ2345")
++ home := shortHome(t)
++ t.Setenv("PYTHONPATH", pythonPath(t))
++ var controls []string
++ oldStatus, oldControl := serviceStatus, serviceControl
++ serviceStatus = func(service.Options) string { return "running" }
++ serviceControl = func(_ service.Options, action string) error { controls = append(controls, action); return nil }
++ defer func() { serviceStatus, serviceControl = oldStatus, oldControl }()
++ out, errOut, code := cli(t, "pair", "--code", "wxyz-2345", "--robot", fakebot.RobotID, "--home", home, "--server", srv.URL())
++ if code != 0 {
++ t.Fatalf("pair failed: %s", errOut)
++ }
++ if len(controls) != 0 {
++ t.Fatalf("the running service was touched: %v", controls)
++ }
++ if !strings.Contains(out, "left alone") || strings.Contains(out, "has been restarted") {
++ t.Fatalf("the output does not say the service was left alone: %s", out)
++ }
++}