| 1 | package edge |
| 2 | |
| 3 | import "testing" |
| 4 | |
| 5 | // privateFleet publishes this edge's own file (annie, in ie, network |
| 6 | // 10.0.0.0/16) and one file per case. |
| 7 | func privateFleet(t *testing.T, m *homeMap) { |
| 8 | t.Helper() |
| 9 | putJSON(t, m.s, "control/edges/annie.json", `{"v":1,"box":"annie","eip":"1.1.1.1","private_ip":"10.0.1.1","private_cidr":"10.0.0.0/16","region":"eu-west-1","placement":"ie","hosts":{}}`) |
| 10 | putJSON(t, m.s, "control/edges/betty.json", `{"v":1,"box":"betty","eip":"2.2.2.2","private_ip":"10.0.1.2","private_cidr":"10.0.0.0/16","region":"eu-west-1","placement":"ie","hosts":{"b.test":{"role":"home"}}}`) |
| 11 | putJSON(t, m.s, "control/edges/carla.json", `{"v":1,"box":"carla","eip":"3.3.3.3","private_ip":"10.1.1.3","private_cidr":"10.1.0.0/16","region":"eu-west-2","placement":"uk","hosts":{"c.test":{"role":"home"}}}`) |
| 12 | putJSON(t, m.s, "control/edges/dora.json", `{"v":1,"box":"dora","eip":"4.4.4.4","region":"eu-west-1","placement":"ie","hosts":{"d.test":{"role":"home"}}}`) |
| 13 | putJSON(t, m.s, "control/edges/edna.json", `{"v":1,"box":"edna","eip":"5.5.5.5","private_ip":"10.0.1.5","region":"eu-west-1","placement":"fleet/shop","hosts":{"e.test":{"role":"home"}}}`) |
| 14 | putJSON(t, m.s, "control/edges/fern.json", `{"v":1,"box":"fern","eip":"","private_ip":"10.0.1.6","region":"eu-west-1","placement":"ie","hosts":{"f.test":{"role":"home"}}}`) |
| 15 | // Addresses a reader refuses: each falls back to the public address. |
| 16 | putJSON(t, m.s, "control/edges/gail.json", `{"v":1,"box":"gail","eip":"7.7.7.7","private_ip":"10.0.1","region":"eu-west-1","placement":"ie","hosts":{"g.test":{"role":"home"}}}`) |
| 17 | putJSON(t, m.s, "control/edges/hana.json", `{"v":1,"box":"hana","eip":"8.8.8.8","private_ip":"169.254.169.254","private_cidr":"169.254.0.0/16","region":"eu-west-1","placement":"ie","hosts":{"h.test":{"role":"home"}}}`) |
| 18 | putJSON(t, m.s, "control/edges/iris.json", `{"v":1,"box":"iris","eip":"9.9.9.9","private_ip":"10.9.1.9","private_cidr":"10.9.0.0/16","region":"eu-west-1","placement":"ie","hosts":{"i.test":{"role":"home"}}}`) |
| 19 | refreshHomeMap(t, m) |
| 20 | } |
| 21 | |
| 22 | // Region HA spec 2 §6: with this edge's region HA on, a box in the same |
| 23 | // region is dialled at its private address and a box in another region at |
| 24 | // its own public address. An address that fails validation against this |
| 25 | // edge's own network is refused, and the dial is public. |
| 26 | func TestHomeMapDialsPrivateWithinTheRegionAndPublicBetween(t *testing.T) { |
| 27 | m := newHomeMap(meshTestStore(t), "annie") |
| 28 | m.privateDial = true |
| 29 | privateFleet(t, m) |
| 30 | for host, want := range map[string]string{ |
| 31 | "b.test": "10.0.1.2", // same region and placement: private |
| 32 | "c.test": "3.3.3.3", // another region: its own public address |
| 33 | "d.test": "4.4.4.4", // a writer with no private_ip: public, as before |
| 34 | "e.test": "5.5.5.5", // same AWS region, another placement: public |
| 35 | "f.test": "10.0.1.6", // no public address, but private within the region |
| 36 | "g.test": "7.7.7.7", // a malformed private address: refused |
| 37 | "h.test": "8.8.8.8", // the metadata range: refused |
| 38 | "i.test": "9.9.9.9", // outside this region's network: refused |
| 39 | } { |
| 40 | if addr, _, ok := m.Home(host); !ok || addr != want { |
| 41 | t.Errorf("%s dials %q (ok=%v), want %q", host, addr, ok, want) |
| 42 | } |
| 43 | } |
| 44 | // An edge whose own file is not in the map knows no region or network |
| 45 | // of its own: every dial is public, and a box with no public address |
| 46 | // is no target. |
| 47 | ghost := newHomeMap(m.s, "ghost") |
| 48 | ghost.privateDial = true |
| 49 | refreshHomeMap(t, ghost) |
| 50 | if addr, _, _ := ghost.Home("b.test"); addr != "2.2.2.2" { |
| 51 | t.Errorf("without its own file: b.test dials %q, want 2.2.2.2", addr) |
| 52 | } |
| 53 | if _, _, ok := ghost.Home("f.test"); ok { |
| 54 | t.Error("without its own file, a box with no public address became a target") |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | // With this edge's region HA off, a peer publishing private_ip changes |
| 59 | // nothing: every dial is public, as on main, during a mixed roll or a |
| 60 | // rollback. |
| 61 | func TestHomeMapWithRegionHAOffDialsPublicOnly(t *testing.T) { |
| 62 | m := newHomeMap(meshTestStore(t), "annie") |
| 63 | privateFleet(t, m) |
| 64 | for host, want := range map[string]string{"b.test": "2.2.2.2", "c.test": "3.3.3.3", "d.test": "4.4.4.4"} { |
| 65 | if addr, _, ok := m.Home(host); !ok || addr != want { |
| 66 | t.Errorf("%s dials %q (ok=%v), want %q", host, addr, ok, want) |
| 67 | } |
| 68 | } |
| 69 | if _, _, ok := m.Home("f.test"); ok { |
| 70 | t.Error("a box with only a private address became a target with region HA off") |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | func TestEdgeHomeMapFollowsRegionHA(t *testing.T) { |
| 75 | e := &Edge{staticStore: meshTestStore(t), box: "annie"} |
| 76 | t.Setenv("CARLOS_REGION_HA", "") |
| 77 | if e.newHomeMap().privateDial { |
| 78 | t.Fatal("region HA unset dials private") |
| 79 | } |
| 80 | t.Setenv("CARLOS_REGION_HA", "1") |
| 81 | if !e.newHomeMap().privateDial { |
| 82 | t.Fatal("region HA on does not dial private") |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | // Astra 2a final review, P2: the home's placement code is "". Two home |
| 87 | // boxes in one AWS region share a placement, so a home edge dials a home |
| 88 | // peer at its private address, under the same guards as a named region: |
| 89 | // the same AWS region, an address inside this edge's own network, and this |
| 90 | // edge's region HA on. A home edge never dials a named-placement box |
| 91 | // privately, nor a named edge a home box, though they share the AWS region |
| 92 | // and the network. |
| 93 | func TestHomeMapDialsHomeBoxesPrivately(t *testing.T) { |
| 94 | m := newHomeMap(meshTestStore(t), "hilda") |
| 95 | privateFleet(t, m) |
| 96 | putJSON(t, m.s, "control/edges/hilda.json", `{"v":1,"box":"hilda","eip":"11.11.11.11","private_ip":"10.0.2.1","private_cidr":"10.0.0.0/16","region":"eu-west-1","placement":"","hosts":{}}`) |
| 97 | putJSON(t, m.s, "control/edges/ivy.json", `{"v":1,"box":"ivy","eip":"12.12.12.12","private_ip":"10.0.2.2","private_cidr":"10.0.0.0/16","region":"eu-west-1","placement":"","hosts":{"ivy.test":{"role":"home"}}}`) |
| 98 | putJSON(t, m.s, "control/edges/jill.json", `{"v":1,"box":"jill","eip":"","private_ip":"10.0.2.3","region":"eu-west-1","hosts":{"jill.test":{"role":"home"}}}`) |
| 99 | putJSON(t, m.s, "control/edges/kim.json", `{"v":1,"box":"kim","eip":"14.14.14.14","private_ip":"10.0.2.4","region":"eu-west-2","placement":"","hosts":{"kim.test":{"role":"home"}}}`) |
| 100 | putJSON(t, m.s, "control/edges/lou.json", `{"v":1,"box":"lou","eip":"15.15.15.15","private_ip":"10.9.2.5","region":"eu-west-1","placement":"","hosts":{"lou.test":{"role":"home"}}}`) |
| 101 | homeWant := map[string]string{ |
| 102 | "ivy.test": "10.0.2.2", // a home peer in the same region: private |
| 103 | "jill.test": "10.0.2.3", // no public address, but private within the home |
| 104 | "kim.test": "14.14.14.14", // a home box in another AWS region: public |
| 105 | "lou.test": "15.15.15.15", // outside this edge's network: refused |
| 106 | "b.test": "2.2.2.2", // a named placement (ie) in the same region: public |
| 107 | } |
| 108 | m.privateDial = true |
| 109 | refreshHomeMap(t, m) |
| 110 | for host, want := range homeWant { |
| 111 | if addr, _, ok := m.Home(host); !ok || addr != want { |
| 112 | t.Errorf("home edge: %s dials %q (ok=%v), want %q", host, addr, ok, want) |
| 113 | } |
| 114 | } |
| 115 | // A named edge (annie, in ie, the same AWS region and network) dials |
| 116 | // every home box at its public address. |
| 117 | named := newHomeMap(m.s, "annie") |
| 118 | named.privateDial = true |
| 119 | refreshHomeMap(t, named) |
| 120 | for host, want := range map[string]string{"ivy.test": "12.12.12.12", "b.test": "10.0.1.2"} { |
| 121 | if addr, _, ok := named.Home(host); !ok || addr != want { |
| 122 | t.Errorf("named edge: %s dials %q (ok=%v), want %q", host, addr, ok, want) |
| 123 | } |
| 124 | } |
| 125 | if _, _, ok := named.Home("jill.test"); ok { |
| 126 | t.Error("named edge: a home box with only a private address became a target") |
| 127 | } |
| 128 | // With this edge's region HA off, the home dials are public, as on main. |
| 129 | off := newHomeMap(m.s, "hilda") |
| 130 | refreshHomeMap(t, off) |
| 131 | if addr, _, _ := off.Home("ivy.test"); addr != "12.12.12.12" { |
| 132 | t.Errorf("region HA off: ivy.test dials %q, want 12.12.12.12", addr) |
| 133 | } |
| 134 | if _, _, ok := off.Home("jill.test"); ok { |
| 135 | t.Error("region HA off: a home box with only a private address became a target") |
| 136 | } |
| 137 | } |
| 138 | |