| 1 | package host |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "github.com/carlosframework/platform/internal/hostbox" |
| 6 | "github.com/carlosframework/platform/internal/hostclaim" |
| 7 | "github.com/carlosframework/platform/internal/lease" |
| 8 | "github.com/carlosframework/platform/internal/park" |
| 9 | "github.com/carlosframework/platform/internal/provision" |
| 10 | "github.com/carlosframework/platform/internal/release" |
| 11 | "testing" |
| 12 | ) |
| 13 | |
| 14 | func TestPlan13ProductionRemoteHomeView(t *testing.T) { |
| 15 | t.Parallel() |
| 16 | f := newVwFixture(t) |
| 17 | f.rec.Region = "" |
| 18 | f.rec.Move = &provision.MoveState{ID: vwMove, Incarnation: f.inc, From: "", To: "uk", State: provision.MoveLanding} |
| 19 | h := f.holder("src", "src@ie") |
| 20 | o := hostclaim.Observed{Host: vwHost, ETag: "tag", Claim: &hostclaim.Claim{Host: vwHost, Holder: h, Op: hostclaim.Op{ID: vwMove, Kind: hostclaim.KindLanding, Phase: "installing", Intent: map[string]string{"home_region": "ie"}}}} |
| 21 | identity := handoverRecoveryIdentity(t, hostbox.Actor{Box: "box", Enrollment: "enrolled", Region: "uk", FleetHomeRegion: "ie", ControlBucket: "control", Revision: 1, Binding: "1"}) |
| 22 | p := productionClaimRegional{Identity: identity, Local: &productionClaimLocal{legacyParticipation: true, Identity: identity, Resources: ClaimRuntimeResources{Mode: "agent", DataDir: t.TempDir()}, assembly: &ClaimAssembly{}, lifetime: t.Context()}, Parks: &claimMoveParkSources{View: f.view("uk")}} |
| 23 | if _, err := p.View(t.Context(), hostclaim.Observed{}); err == nil { |
| 24 | t.Fatal("missing claim accepted") |
| 25 | } |
| 26 | v, err := p.View(t.Context(), o) |
| 27 | if err != nil { |
| 28 | t.Fatal(err) |
| 29 | } |
| 30 | if v.AuthoritativeRegion != park.HomeRegion || v.Region != "uk" || v.HomeRegion != "ie" { |
| 31 | t.Fatalf("view: %+v", v) |
| 32 | } |
| 33 | if h.Admissions[0].Region != "ie" { |
| 34 | t.Fatal("history rewritten") |
| 35 | } |
| 36 | ob := hostclaim.Obligation{ID: "persisted", Kind: "park-generation", Op: vwMove, Owner: "region:uk", Region: "uk", Generation: "old", Retirement: "retirement"} |
| 37 | store := release.NewDirStore(t.TempDir()) |
| 38 | op := o.Claim.Op |
| 39 | o, err = hostclaim.Update(t.Context(), store, hostclaim.Observed{Host: vwHost, Absent: true}, func(c *hostclaim.Claim) error { |
| 40 | c.Holder = h |
| 41 | c.Op = op |
| 42 | c.Obligations = []hostclaim.Obligation{ob} |
| 43 | return nil |
| 44 | }) |
| 45 | if err != nil { |
| 46 | t.Fatal(err) |
| 47 | } |
| 48 | o, err = hostclaim.Read(t.Context(), store, vwHost) |
| 49 | if err != nil { |
| 50 | t.Fatal(err) |
| 51 | } |
| 52 | if err := p.Authorize(t.Context(), o, ob); err != nil { |
| 53 | t.Fatal("authorized control", err) |
| 54 | } |
| 55 | ob.Owner, ob.Region = "region:@home", park.HomeRegion |
| 56 | o, err = hostclaim.Update(t.Context(), store, o, func(c *hostclaim.Claim) error { c.Obligations = []hostclaim.Obligation{ob}; return nil }) |
| 57 | if err != nil { |
| 58 | t.Fatal(err) |
| 59 | } |
| 60 | o, err = hostclaim.Read(t.Context(), store, vwHost) |
| 61 | if err != nil { |
| 62 | t.Fatal(err) |
| 63 | } |
| 64 | if err := p.Authorize(t.Context(), o, ob); err == nil { |
| 65 | t.Fatal("named worker owns home") |
| 66 | } |
| 67 | } |
| 68 | func TestPlan13MovesEngineBindings(t *testing.T) { |
| 69 | withMovesWakeSource(t, true) |
| 70 | for _, home := range []string{"ie", ""} { |
| 71 | region := "uk" |
| 72 | if home != "" { |
| 73 | region = "ie" |
| 74 | } |
| 75 | e := park.Engine{HomeRegion: home, Region: region, Bucket: "data", Leases: claimParkLeases(&fakeParkLeases{}), View: func(context.Context, hostclaim.Observed) (park.View, error) { return park.View{}, nil }, Authorize: allowParkAuthorize} |
| 76 | providers := ClaimProviders{moveParks: &claimMoveParks{engine: e, leases: hostbox.ReplicaParkLeaseSet, local: func(context.Context, *hostclaim.Claim, hostclaim.Obligation) error { return nil }, check: func(context.Context) error { return nil }}} |
| 77 | cfg := moveCfg{Region: region, OwnBucket: "data"} |
| 78 | if home != "" { |
| 79 | cfg.Region = "" |
| 80 | } |
| 81 | if err := armMovesParks(t.Context(), &cfg, providers); err != nil { |
| 82 | t.Fatal(err) |
| 83 | } |
| 84 | w := &movesWorker{cfg: cfg} |
| 85 | engines := []park.Engine{(&installRun{w: w}).engine(nil), (&sourceFinal{w: w}).engine(nil), (&rollbackRun{w: w}).engine(nil)} |
| 86 | for _, got := range engines { |
| 87 | if got.HomeRegion != home || !got.OwnsRegion(park.PlacementRegion(cfg.Region)) { |
| 88 | t.Fatalf("binding lost: %+v", got) |
| 89 | } |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | func TestPlan13HomeLaneEngineBinding(t *testing.T) { |
| 95 | withMovesWakeSource(t, true) |
| 96 | h := newAbortHarness(t) |
| 97 | h.abort(t) |
| 98 | h.pass(t) |
| 99 | chore := h.laneChore(t) |
| 100 | if chore == nil { |
| 101 | t.Fatal("no chore") |
| 102 | } |
| 103 | h.pastHorizon(t, chore) |
| 104 | cfg := h.laneCfg() |
| 105 | cfg.Region = "" |
| 106 | engine := park.Engine{Region: "uk", HomeRegion: "uk", Bucket: cfg.OwnBucket, Leases: cfg.ParkLeases, Authorize: allowParkAuthorize, View: func(_ context.Context, o hostclaim.Observed) (park.View, error) { |
| 107 | return park.View{Region: park.HomeRegion, ClaimETag: o.ETag, AuthoritativeRegion: "ie"}, nil |
| 108 | }} |
| 109 | p := ClaimProviders{moveParks: &claimMoveParks{engine: engine, leases: hostbox.ReplicaParkLeaseSet, local: func(context.Context, *hostclaim.Claim, hostclaim.Obligation) error { return nil }, check: func(context.Context) error { return nil }}} |
| 110 | if err := armMovesParks(t.Context(), &cfg, p); err != nil { |
| 111 | t.Fatal(err) |
| 112 | } |
| 113 | o, err := hostclaim.Read(t.Context(), h.s, p1Host) |
| 114 | if err != nil { |
| 115 | t.Fatal(err) |
| 116 | } |
| 117 | if _, err = hostclaim.Update(t.Context(), h.s, o, func(c *hostclaim.Claim) error { c.Op.Intent["home_region"] = "uk"; return nil }); err != nil { |
| 118 | t.Fatal(err) |
| 119 | } |
| 120 | rec := h.read(t, p1Host) |
| 121 | rec.Move.To = "" |
| 122 | worker := &movesWorker{cfg: cfg, mirrors: map[string]lease.MirrorStore{}} |
| 123 | if err := worker.laneParkTarget(t.Context(), h.s, rec, hostclaim.KindMoving, hostclaim.PhaseAborting); err != nil { |
| 124 | t.Fatal(err) |
| 125 | } |
| 126 | if h.laneChore(t) != nil { |
| 127 | t.Fatal("named home chore was not acknowledged") |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | func TestPlan13MovesViewMapsAllHomePlacements(t *testing.T) { |
| 132 | for _, moving := range []bool{false, true} { |
| 133 | f := newVwFixture(t) |
| 134 | f.rec.Region = "" |
| 135 | h := f.holder("") |
| 136 | op := hostclaim.Op{Kind: hostclaim.KindServing} |
| 137 | if moving { |
| 138 | h = f.holder("src", "src@ie") |
| 139 | op = hostclaim.Op{Kind: hostclaim.KindMoving, ID: vwMove, Intent: map[string]string{"home_region": "ie"}} |
| 140 | f.rec.Move = &provision.MoveState{ID: vwMove, Incarnation: f.inc, From: "", To: "uk", State: provision.MoveCutting} |
| 141 | } |
| 142 | v, err := f.view(park.HomeRegion)(t.Context(), vwObs(&hostclaim.Claim{Holder: h, Op: op})) |
| 143 | if !moving { |
| 144 | if err == nil { |
| 145 | t.Fatal("unbound legacy home accepted") |
| 146 | } |
| 147 | continue |
| 148 | } |
| 149 | if err != nil || v.AuthoritativeRegion != park.HomeRegion || !v.MarkerKnown { |
| 150 | t.Fatal(moving, v, err) |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | |