zfs: a follower reaches the keeper's socket on every call, so a keeper up later is used (A-37, reviewer's note)
Builds: design 42 zfs-owns-zfs A-37
This commit is contained in:
@@ -36,7 +36,7 @@ func (b busStates) Get(state, key string) (json.RawMessage, bool, error) {
|
||||
}
|
||||
|
||||
// JoinBus gives a root process the module's events and states through the keeper's socket (A-37): the process holds no
|
||||
// bus account of its own. Without the socket the machine keeps none, and what it changes is said as a warning (§18:
|
||||
// bus account of its own. Without the socket variable the machine keeps none, and what it changes is said as a warning (§18:
|
||||
// with the bus down the apply converges from the config file it last got). It answers how to leave the bus.
|
||||
func (m *Machine) JoinBus() func() {
|
||||
sock := strings.TrimSpace(os.Getenv(KeeperSocketEnv))
|
||||
@@ -44,12 +44,9 @@ func (m *Machine) JoinBus() func() {
|
||||
m.Warnings = append(m.Warnings, KeeperSocketEnv+" is not set, so the keeper is not reached and the bus is taken as down")
|
||||
return func() {}
|
||||
}
|
||||
// Every call reaches the socket anew, so a keeper that comes up after this process is used from then on; one that
|
||||
// is down at a call answers that call with an error, never the bus taken as down for the process's life.
|
||||
c := keeperClient{sock}
|
||||
// The keeper answering is what the bus being up means: one call says it before the process relies on it.
|
||||
if _, err := c.Keys(StateSchedule); err != nil {
|
||||
m.Warnings = append(m.Warnings, err.Error()+": the bus is taken as down")
|
||||
return func() {}
|
||||
}
|
||||
m.Emit = c.emit
|
||||
m.States = c
|
||||
m.Findings = meshconditionsclient.FindingWriter{State: findingState{c}}
|
||||
|
||||
@@ -106,14 +106,36 @@ func TestOnlyRootOpensTheKeepersSocketAndANeedlessKeeperIsTheBusDown(t *testing.
|
||||
if _, left := st["schedule/x"]; left {
|
||||
t.Errorf("a refused peer's call was read")
|
||||
}
|
||||
// No keeper: the machine keeps no bus and says so.
|
||||
t.Setenv(KeeperSocketEnv, filepath.Join(dir, "none.sock"))
|
||||
// No socket variable: the machine keeps no bus and says so.
|
||||
t.Setenv(KeeperSocketEnv, "")
|
||||
m := newFake(t).machine()
|
||||
m.Emit = nil
|
||||
m.JoinBus()
|
||||
if m.Emit != nil || m.States != nil || len(m.Warnings) != 1 || !strings.Contains(m.Warnings[0], "bus is taken as down") {
|
||||
t.Errorf("no keeper: %+v", m.Warnings)
|
||||
}
|
||||
// A keeper not yet up: the process joins, its calls fail, and the same process uses the keeper once it is up.
|
||||
late := filepath.Join(dir, "late.sock")
|
||||
t.Setenv(KeeperSocketEnv, late)
|
||||
ml := newFake(t).machine()
|
||||
ml.JoinBus()
|
||||
if ml.States == nil {
|
||||
t.Fatalf("a keeper not up yet must not take the bus as down: %+v", ml.Warnings)
|
||||
}
|
||||
if _, err := ml.States.Keys(StateSchedule); err == nil {
|
||||
t.Errorf("no keeper up, yet a call answered")
|
||||
}
|
||||
ll, err := Listen(late)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lctx, lcancel := context.WithCancel(context.Background())
|
||||
defer lcancel()
|
||||
go (&Keeper{Emit: func(string, any) error { return nil }, States: memStates{}, PeerOf: func(net.Conn) (int, error) { return 0, nil },
|
||||
Call: func(string, any) (json.RawMessage, error) { return nil, nil }}).Serve(lctx, ll)
|
||||
if _, err := ml.States.Keys(StateSchedule); err != nil {
|
||||
t.Errorf("a keeper that came up later is not used: %v", err)
|
||||
}
|
||||
t.Setenv(KeeperSocketEnv, sock)
|
||||
uid = 0
|
||||
m2 := newFake(t).machine()
|
||||
|
||||
Reference in New Issue
Block a user