openvibers/openvibe.link Commits
Fix latch file ownership after a root stop/resume without a running node; log files on macOS; honest log docs
Changes
@@@ -331,6 +331,7 @@ func cmdStop(g *globals, stdout io.Writer) error {if ferr := safety.WriteLocalFile(g.paths.LatchFile(), true); ferr != nil {return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)}++ chownLikeDir(g.paths.LatchFile(), g.paths.StateDir) // the service account must be able to read itfmt.Fprintln(stdout, "The node did not answer; the stop is latched in", g.paths.LatchFile())fmt.Fprintln(stdout, "A running node obeys it within a quarter second; a starting node starts stopped. Release with `openvibe-node resume`.")return nil@@@ -342,6 +343,7 @@ func cmdResume(g *globals, stdout io.Writer) error {if ferr := safety.WriteLocalFile(g.paths.LatchFile(), false); ferr != nil {return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)}++ chownLikeDir(g.paths.LatchFile(), g.paths.StateDir)}fmt.Fprintln(stdout, "Resumed: the local stop and any server e-stop are released. Operators can drive again.")return nil@@@ -128,7 +128,8 @@ internet (Ethernet, or a second Wi-Fi adapter). Install with `--robot cozmo`; th- `openvibe-node status` shows the last link error. "the server refused the device credential" means it was revoked:`sudo openvibe-node pair --force <NEW-CODE>`.--- Logs: `journalctl -u openvibe-node -f` (Linux), `/var/log/openvibe-node.*.log` (macOS), Event Viewer (Windows).++- Logs: `journalctl -u openvibe-node -f` (Linux), `/usr/local/var/log/openvibe-node.err.log` (macOS). On Windows the++ service's log is not kept yet; stop the service and run `openvibe-node run` in a terminal to watch it.- A plugin in `faulted` state says why in `status` (missing library, not a Raspberry Pi, robot not reachable, firmware).- `openvibe-node plugins` works without the service running: it asks each plugin to describe itself without touchinghardware.@@@ -5,6 +5,7 @@ package serviceimport ("context""errors"++ "runtime""sync""time"@@@ -73,7 +74,7 @@ type Options struct {}func config(opt Options) *ks.Config {-- return &ks.Config{++ c := &ks.Config{Name: Name, DisplayName: DisplayName, Description: Description, Arguments: opt.Arguments, UserName: opt.UserName,Option: ks.KeyValue{"Restart": "always", // systemd@@@ -85,6 +86,11 @@ func config(opt Options) *ks.Config {"DelayedAutoStart": false,},}++ if runtime.GOOS == "darwin" {++ // launchd has no journal: write /usr/local/var/log/openvibe-node.{out,err}.log. systemd keeps journald.++ c.Option["LogOutput"] = true++ }++ return c}// Run runs program under the service manager, or in the foreground when started from a terminal.
@@ -331,6 +331,7 @@ func cmdStop(g *globals, stdout io.Writer) error {
@@ -331,6 +331,7 @@ func cmdStop(g *globals, stdout io.Writer) error {
if ferr := safety.WriteLocalFile(g.paths.LatchFile(), true); ferr != nil {
if ferr := safety.WriteLocalFile(g.paths.LatchFile(), true); ferr != nil {
return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)
return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)
}
}
+ chownLikeDir(g.paths.LatchFile(), g.paths.StateDir) // the service account must be able to read it
fmt.Fprintln(stdout, "The node did not answer; the stop is latched in", g.paths.LatchFile())
fmt.Fprintln(stdout, "The node did not answer; the stop is latched in", g.paths.LatchFile())
fmt.Fprintln(stdout, "A running node obeys it within a quarter second; a starting node starts stopped. Release with `openvibe-node resume`.")
fmt.Fprintln(stdout, "A running node obeys it within a quarter second; a starting node starts stopped. Release with `openvibe-node resume`.")
return nil
return nil
@@ -342,6 +343,7 @@ func cmdResume(g *globals, stdout io.Writer) error {
@@ -342,6 +343,7 @@ func cmdResume(g *globals, stdout io.Writer) error {
if ferr := safety.WriteLocalFile(g.paths.LatchFile(), false); ferr != nil {
if ferr := safety.WriteLocalFile(g.paths.LatchFile(), false); ferr != nil {
return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)
return fmt.Errorf("could not reach the node (%v) nor write %s (%v); run with sudo", err, g.paths.LatchFile(), ferr)
}
}
+ chownLikeDir(g.paths.LatchFile(), g.paths.StateDir)
}
}
fmt.Fprintln(stdout, "Resumed: the local stop and any server e-stop are released. Operators can drive again.")
fmt.Fprintln(stdout, "Resumed: the local stop and any server e-stop are released. Operators can drive again.")
return nil
return nil
@@ -128,7 +128,8 @@ internet (Ethernet, or a second Wi-Fi adapter). Install with `--robot cozmo`; th
@@ -128,7 +128,8 @@ internet (Ethernet, or a second Wi-Fi adapter). Install with `--robot cozmo`; th
- `openvibe-node status` shows the last link error. "the server refused the device credential" means it was revoked:
- `openvibe-node status` shows the last link error. "the server refused the device credential" means it was revoked:
`sudo openvibe-node pair --force <NEW-CODE>`.
`sudo openvibe-node pair --force <NEW-CODE>`.
-- Logs: `journalctl -u openvibe-node -f` (Linux), `/var/log/openvibe-node.*.log` (macOS), Event Viewer (Windows).
+- Logs: `journalctl -u openvibe-node -f` (Linux), `/usr/local/var/log/openvibe-node.err.log` (macOS). On Windows the
+ service's log is not kept yet; stop the service and run `openvibe-node run` in a terminal to watch it.
- A plugin in `faulted` state says why in `status` (missing library, not a Raspberry Pi, robot not reachable, firmware).
- A plugin in `faulted` state says why in `status` (missing library, not a Raspberry Pi, robot not reachable, firmware).
- `openvibe-node plugins` works without the service running: it asks each plugin to describe itself without touching
- `openvibe-node plugins` works without the service running: it asks each plugin to describe itself without touching
hardware.
hardware.
@@ -5,6 +5,7 @@ package service
@@ -5,6 +5,7 @@ package service
import (
import (
"context"
"context"
"errors"
"errors"
+ "runtime"
"sync"
"sync"
"time"
"time"
@@ -73,7 +74,7 @@ type Options struct {
@@ -73,7 +74,7 @@ type Options struct {
}
}
func config(opt Options) *ks.Config {
func config(opt Options) *ks.Config {
- return &ks.Config{
+ c := &ks.Config{
Name: Name, DisplayName: DisplayName, Description: Description, Arguments: opt.Arguments, UserName: opt.UserName,
Name: Name, DisplayName: DisplayName, Description: Description, Arguments: opt.Arguments, UserName: opt.UserName,
Option: ks.KeyValue{
Option: ks.KeyValue{
"Restart": "always", // systemd
"Restart": "always", // systemd
@@ -85,6 +86,11 @@ func config(opt Options) *ks.Config {
@@ -85,6 +86,11 @@ func config(opt Options) *ks.Config {
"DelayedAutoStart": false,
"DelayedAutoStart": false,
},
},
}
}
+ if runtime.GOOS == "darwin" {
+ // launchd has no journal: write /usr/local/var/log/openvibe-node.{out,err}.log. systemd keeps journald.
+ c.Option["LogOutput"] = true
+ }
+ return c
}
}
// Run runs program under the service manager, or in the foreground when started from a terminal.
// Run runs program under the service manager, or in the foreground when started from a terminal.