//go:build linux package host import ( "context" "encoding/json" "os" "path/filepath" "testing" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostclaim" execlease "github.com/carlosframework/platform/internal/hostexec" "github.com/carlosframework/platform/internal/hostguard" "github.com/carlosframework/platform/internal/provision" ) func TestPlan14CreateParticipationBeforeInstallation(t *testing.T) { t.Parallel() f, root, _ := plan14InstallRegistration(t, hostclaim.KindServing, "") before := f.read() h := before.Claim.Holder rec := provision.Record{Schema: 1, Host: before.Host, Account: h.Account, App: h.App, Channel: "stable", Region: "ie", CreatedAt: f.now} body, err := json.Marshal(rec) if err != nil { t.Fatal(err) } created, err := hostclaim.Update(t.Context(), f.claims, before, func(c *hostclaim.Claim) error { *c = hostclaim.Claim{V: c.V, Host: c.Host, Gen: c.Gen} return hostclaim.BeginSelectedCreate(hostclaim.NewHolder{Host: rec.Host, Account: rec.Account, App: rec.App, Family: "instance", Key: h.Key, Region: "ie", RecordRegion: "ie", CreatedAt: rec.CreatedAt}, body, "create", "test", f.now, "box-1", "en", "app-id", 1, "own", "record")(c) }) if err != nil { t.Fatal(err) } q := execlease.ExecutionRequest{Schema: 1, ID: "begin", Operation: "executionBegin", Host: created.Host, Incarnation: created.Claim.Holder.Incarnation, Op: created.Claim.Op.ID} if !q.Valid() { t.Fatal("create participation request refused") } a, err := root.executionAuthority(t.Context(), q, execlease.ControllerProcess{}) if err != nil || !a.ParticipationOnly || a.Installation != "" || a.Kind != hostclaim.KindCreating { t.Fatalf("create authority: %+v %v", a, err) } if _, err = root.Stop.Coordinator.Guard.Root.View(t.Context(), q.Host, hostguard.Captured{Incarnation: q.Incarnation}); err == nil { t.Fatal("participation installed root authority") } for _, attack := range []string{"session", "stamp", "operation", "enrollment", "artifact"} { t.Run(attack, func(t *testing.T) { request, handler := q, root switch attack { case "session": request.Session = 1 case "stamp": request.Stamp = 1 case "operation": request.Op = "other" case "enrollment": actor, e := root.InventoryActor(t.Context()) if e != nil { t.Fatal(e) } actor.Enrollment = "foreign" handler.InventoryActor = func(context.Context) (hostbox.Actor, error) { return actor, nil } case "artifact": path := filepath.Join(root.Roots["data"], "unaccounted") if err := os.WriteFile(path, []byte("old state"), 0600); err != nil { t.Fatal(err) } defer os.Remove(path) } if _, err := handler.executionAuthority(t.Context(), request, execlease.ControllerProcess{}); err == nil { t.Fatal("unauthorized create participation") } }) } } func TestPlan14CreateAcknowledgementProductionClient(t *testing.T) { f, root, _, _, local := productionExecutionFixture(t, hostclaim.KindLanding) before := f.read() h := before.Claim.Holder rec := provision.Record{Schema: 1, Host: before.Host, Account: h.Account, App: h.App, Channel: "stable", Region: "ie", CreatedAt: f.now} body, err := json.Marshal(rec) if err != nil { t.Fatal(err) } _, err = hostclaim.Update(t.Context(), f.claims, before, func(c *hostclaim.Claim) error { *c = hostclaim.Claim{V: c.V, Host: c.Host, Gen: c.Gen} return hostclaim.BeginSelectedCreate(hostclaim.NewHolder{Host: rec.Host, Account: rec.Account, App: rec.App, Family: "instance", Key: h.Key, Region: "ie", RecordRegion: "ie", CreatedAt: rec.CreatedAt}, body, "create", "test", f.now, "box-1", "en", "app-id", 1, "own", "record")(c) }) if err != nil { t.Fatal(err) } actor, err := root.InventoryActor(t.Context()) if err != nil { t.Fatal(err) } if err = local.participateHost(t.Context(), actor, rec.Host); err != nil { t.Fatal("participate and acknowledge", err) } observed := f.read() var ack hostclaim.ExecutionAcknowledgement if err = json.Unmarshal([]byte(observed.Claim.Op.Journal["exec_ack."+actor.Box]), &ack); err != nil { t.Fatal("missing production acknowledgement", err) } state, err := local.slots[rec.Host].Controller.Ready(t.Context()) if err != nil { t.Fatal(err) } if ack.Op != state.Op || ack.Enrollment != state.Enrollment || ack.LeaseETag != state.LeaseETag || ack.ControllerID != state.ControllerID || ack.BootID != state.BootID || !ack.Expires.Equal(state.Expires) { t.Fatal("acknowledgement differs from root lease", ack, state) } if err = local.participateHost(t.Context(), actor, rec.Host); err != nil { t.Fatal("acknowledgement replay", err) } if got := f.read().Claim.Op.Journal["exec_ack."+actor.Box]; got != observed.Claim.Op.Journal["exec_ack."+actor.Box] { t.Fatal("acknowledgement replaced") } completed, err := hostclaim.Update(t.Context(), f.claims, f.read(), hostclaim.CompleteCreate("create", actor.Box)) if err != nil { t.Fatal(err) } if err = local.prepareWith(t.Context(), actor, completed); err != nil { t.Fatal("settle create before installation", err) } }