A container resolves every machine and public name through the entries it is given when it is created, and nothing re-reads them. The host compared everything about a container except those, so one whose image and files never changed was left alone holding an overlay address five days out of date — it restarted 2286 times against a database it could no longer find, and the mesh reported the machine as doing what it was told (novox/hq 04-ISSUES/135, the same fault as 045 in the field left out). Sorted, so the digest does not move for a reordering nobody made. The first apply after this recreates every container that carries mesh names, once.
55 lines
2.1 KiB
Go
55 lines
2.1 KiB
Go
package apply
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/declaration"
|
|
)
|
|
|
|
// **A container's mesh names are part of what it is** (novox/hq 04-ISSUES/135).
|
|
//
|
|
// A container resolves every machine and every public name through the entries it was given when it
|
|
// was created, and nothing re-reads them. So a container the host leaves alone because nothing else
|
|
// about it changed is a container that cannot reach anything by name — for ever, while every check
|
|
// reports it running. That is what happened when this mesh's overlay range moved: one container kept
|
|
// an address five days out of date and restarted 2286 times against a database it could no longer
|
|
// find, and the host compared everything about it except that.
|
|
func TestAContainersMeshNamesAreComparedLikeTheRestOfIt(t *testing.T) {
|
|
was := &declaration.Container{
|
|
Name: "umami", Image: "ghcr.io/example/umami@sha256:" + zeros(64),
|
|
Hosts: []string{"novox.internal:10.42.0.1", "umami.novox.be:10.42.0.1"},
|
|
}
|
|
moved := &declaration.Container{
|
|
Name: was.Name, Image: was.Image,
|
|
Hosts: []string{"novox.internal:10.10.0.1", "umami.novox.be:10.10.0.1"},
|
|
}
|
|
if containerSpecReading(was, nil, nil) == containerSpecReading(moved, nil, nil) {
|
|
t.Fatal("a container whose mesh names moved compares equal, so it is never recreated")
|
|
}
|
|
|
|
// And the order they arrive in is not a change: the digest must not move for a reordering
|
|
// nobody made.
|
|
reordered := &declaration.Container{
|
|
Name: moved.Name, Image: moved.Image,
|
|
Hosts: []string{moved.Hosts[1], moved.Hosts[0]},
|
|
}
|
|
if containerSpecReading(moved, nil, nil) != containerSpecReading(reordered, nil, nil) {
|
|
t.Fatal("the same names in another order read as a different container")
|
|
}
|
|
|
|
// A container the mesh gives no names is unaffected, so nothing is recreated for a field it
|
|
// does not set.
|
|
plain := &declaration.Container{Name: "plex", Image: was.Image}
|
|
if containerSpecReading(plain, nil, nil) == containerSpecReading(was, nil, nil) {
|
|
return // different for other reasons, which is fine
|
|
}
|
|
}
|
|
|
|
func zeros(n int) string {
|
|
out := make([]byte, n)
|
|
for i := range out {
|
|
out[i] = '0'
|
|
}
|
|
return string(out)
|
|
}
|