Do not remove keys or entries before the machines' keys are read (issue 955 F)
mesh/merge-gate head 6f45570d4c23 merged into trunk 017b729bc95d — fail: builds gitea, ssh-client → ace, g14, novox, shanks; no bus step; 4 problem(s) the …
mesh/repo-check head 6f45570d4c23 merged into trunk 017b729bc95d — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery-group group feat/agents-write-git-ssh rejected: a member's own check failed
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate head 6f45570d4c23 merged into trunk 017b729bc95d — fail: builds gitea, ssh-client → ace, g14, novox, shanks; no bus step; 4 problem(s) the …
mesh/repo-check head 6f45570d4c23 merged into trunk 017b729bc95d — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery-group group feat/agents-write-git-ssh rejected: a member's own check failed
mesh/delivery superseded: a newer head of the same pull request
This commit is contained in:
@@ -62,9 +62,10 @@ type Service struct {
|
|||||||
// Pause waits between asks of a watch the runtime does not answer yet.
|
// Pause waits between asks of a watch the runtime does not answer yet.
|
||||||
Pause func(time.Duration)
|
Pause func(time.Duration)
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
keys map[string]machineKey
|
keys map[string]machineKey
|
||||||
known string // the forge's host key line, as the machines write it into known_hosts
|
loaded bool // the machines' keys have been read: until then a node with none has not reported none
|
||||||
|
known string // the forge's host key line, as the machines write it into known_hosts
|
||||||
|
|
||||||
bound provider.Bus // the bus the entries are written to (set by Provider)
|
bound provider.Bus // the bus the entries are written to (set by Provider)
|
||||||
|
|
||||||
@@ -117,6 +118,13 @@ func (s *Service) Make(ctx context.Context, c provider.Consumer) error {
|
|||||||
if user == "" {
|
if user == "" {
|
||||||
return fmt.Errorf("%q is not a machine's name an account can be named for", node)
|
return fmt.Errorf("%q is not a machine's name an account can be named for", node)
|
||||||
}
|
}
|
||||||
|
s.mu.Lock()
|
||||||
|
loaded := s.loaded
|
||||||
|
s.mu.Unlock()
|
||||||
|
if !loaded {
|
||||||
|
// After a restart the first pass can come before the keys arrive: nothing is removed or deleted on that.
|
||||||
|
return errors.New("the machines' keys are not read yet, so nothing is made, removed or deleted")
|
||||||
|
}
|
||||||
have := s.keysOf(node)
|
have := s.keysOf(node)
|
||||||
if len(have) == 0 {
|
if len(have) == 0 {
|
||||||
// A key the machine no longer reports is no longer wanted (ADR 0400 §2): the mesh's keys go, the operator's
|
// A key the machine no longer reports is no longer wanted (ADR 0400 §2): the mesh's keys go, the operator's
|
||||||
@@ -253,6 +261,10 @@ func (s *Service) WatchKeys(ctx context.Context, src KeySource) error {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
// The watch answers once the current values are all handled (stdio KeptState.Watch).
|
||||||
|
s.mu.Lock()
|
||||||
|
s.loaded = true
|
||||||
|
s.mu.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pause := time.Minute
|
pause := time.Minute
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ func newRig(t *testing.T) *rig {
|
|||||||
svc := NewService(Config{Node: "novox", HostFile: host, OriginsFile: origins, Port: 222,
|
svc := NewService(Config{Node: "novox", HostFile: host, OriginsFile: origins, Port: 222,
|
||||||
Forge: forgehttp.Client{URL: srv.URL, User: "mesh-admin", PasswordFile: pw}, Runner: runner,
|
Forge: forgehttp.Client{URL: srv.URL, User: "mesh-admin", PasswordFile: pw}, Runner: runner,
|
||||||
Log: func(string, ...any) {}})
|
Log: func(string, ...any) {}})
|
||||||
|
svc.loaded = true // the machines' keys are read; a test that means otherwise says so
|
||||||
return &rig{t: t, bus: newBus(), forge: forge, svc: svc, runner: runner}
|
return &rig{t: t, bus: newBus(), forge: forge, svc: svc, runner: runner}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,11 +378,15 @@ func TestKeysWatchedRetriesUntilItAnswersAndPassesOnChanges(t *testing.T) {
|
|||||||
r := newRig(t)
|
r := newRig(t)
|
||||||
src := &fakeKeys{failFirst: 2}
|
src := &fakeKeys{failFirst: 2}
|
||||||
r.svc.Pause = func(time.Duration) {}
|
r.svc.Pause = func(time.Duration) {}
|
||||||
|
r.svc.loaded = false
|
||||||
passes := 0
|
passes := 0
|
||||||
r.svc.OnKeys = func(string) { passes++ }
|
r.svc.OnKeys = func(string) { passes++ }
|
||||||
if err := r.svc.WatchKeys(context.Background(), src); err != nil {
|
if err := r.svc.WatchKeys(context.Background(), src); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if !r.svc.loaded {
|
||||||
|
t.Fatal("the keys are not loaded once the watch has answered")
|
||||||
|
}
|
||||||
if src.calls != 3 {
|
if src.calls != 3 {
|
||||||
t.Fatalf("asked %d times", src.calls)
|
t.Fatalf("asked %d times", src.calls)
|
||||||
}
|
}
|
||||||
@@ -433,3 +438,36 @@ func TestADeletedKeyEntryRemovesTheMeshKeyAndTheBoundEntryButNotTheOperatorsKey(
|
|||||||
t.Fatal("the entry still serves a machine whose key is gone")
|
t.Fatal("the entry still serves a machine whose key is gone")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPassBeforeTheKeysAreLoadedRemovesAndDeletesNothing(t *testing.T) {
|
||||||
|
r := newRig(t)
|
||||||
|
r.bus.bindClient("g14")
|
||||||
|
r.key("g14", "nox", pubA+" nox@g14 (mesh)")
|
||||||
|
r.pass()
|
||||||
|
r.forge.mu.Lock()
|
||||||
|
r.forge.held["agent-g14"] = append(r.forge.held["agent-g14"], map[string]any{"id": int64(99), "title": "my own", "key": pubB})
|
||||||
|
r.forge.mu.Unlock()
|
||||||
|
// A restart: the keys are not read yet, so a node with none is not a node that reported none.
|
||||||
|
r.svc.mu.Lock()
|
||||||
|
r.svc.keys = map[string]machineKey{}
|
||||||
|
r.svc.loaded = false
|
||||||
|
r.svc.mu.Unlock()
|
||||||
|
out := r.pass()
|
||||||
|
if got := strings.Join(r.forge.titles("agent-g14"), ","); got != "mesh:g14.nox,my own" {
|
||||||
|
t.Fatalf("keys = %s", got)
|
||||||
|
}
|
||||||
|
if !r.bus.has("g14.ssh-client.forge-account") {
|
||||||
|
t.Fatal("the entry was deleted before the keys were read")
|
||||||
|
}
|
||||||
|
if len(out) != 1 || !strings.Contains(out[0].Why, "not read yet") {
|
||||||
|
t.Fatalf("the wait should be said: %+v", out)
|
||||||
|
}
|
||||||
|
// Loaded, and the node reports none: now its keys go.
|
||||||
|
r.svc.mu.Lock()
|
||||||
|
r.svc.loaded = true
|
||||||
|
r.svc.mu.Unlock()
|
||||||
|
r.pass()
|
||||||
|
if got := strings.Join(r.forge.titles("agent-g14"), ","); got != "my own" || r.bus.has("g14.ssh-client.forge-account") {
|
||||||
|
t.Fatalf("keys = %s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user