Download this file
| 1 | package hostfence |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "github.com/carlosframework/platform/internal/hostclaim" |
| 6 | "slices" |
| 7 | ) |
| 8 | |
| 9 | // CheckOneBoxRegion uses the same signed roster as fence authority. A fenced |
| 10 | // source still counts; neither a missing heartbeat nor a second fenced box |
| 11 | // turns a two-box placement into a one-box region. |
| 12 | func (a ClaimFenceAuthority) CheckOneBoxRegion(ctx context.Context, source, region string) error { |
| 13 | o, err := a.Directory.Read(ctx) |
| 14 | if err != nil { |
| 15 | return err |
| 16 | } |
| 17 | b, ok := o.Roster.Boxes[source] |
| 18 | if !ok || b.Region != region { |
| 19 | return hostclaim.ErrFence |
| 20 | } |
| 21 | placement, ok := o.Roster.Regions[region] |
| 22 | if !ok || placement.Account != b.Cloud.Account || placement.AWSRegion != b.Cloud.Region || !slices.Contains(placement.Namespaces, b.Namespace) || !slices.Contains(placement.Pools, b.Pool) { |
| 23 | return hostclaim.ErrFence |
| 24 | } |
| 25 | count := 0 |
| 26 | for _, candidate := range o.Roster.Boxes { |
| 27 | if candidate.Region == region && candidate.Namespace == b.Namespace && candidate.Pool == b.Pool && candidate.State != "retired" { |
| 28 | count++ |
| 29 | } |
| 30 | } |
| 31 | if b.State == "retired" || count != 1 { |
| 32 | return hostclaim.ErrFence |
| 33 | } |
| 34 | return nil |
| 35 | } |
| 36 | |