package cluster var ( _ MachineIterator = (*Region)(nil) _ ZoneIterator = (*Region)(nil) ) // Region represents a group of zones geographically related type Region struct { m *Cluster zones []*Zone Name string Regions []string `json:",omitempty" yaml:",omitempty"` } // ForEachRegion calls a function for each Region of the cluster // until instructed to terminate the loop func (m *Cluster) ForEachRegion(fn func(r *Region) bool) { for i := range m.Regions { r := &m.Regions[i] if fn(r) { return } } } // ForEachMachine calls a function for each Machine in the region // until instructed to terminate the loop func (r *Region) ForEachMachine(fn func(*Machine) bool) { r.ForEachZone(func(z *Zone) bool { var term bool z.ForEachMachine(func(p *Machine) bool { if p.IsActive() { term = fn(p) } return term }) return term }) } // ForEachZone calls a function for each Zone in the region // until instructed to terminate the loop func (r *Region) ForEachZone(fn func(*Zone) bool) { for _, p := range r.zones { if fn(p) { // terminate return } } } func (m *Cluster) initRegions(_ *ScanOptions) error { regions := make(map[string][]*Zone) // first regions defined by zones m.ForEachZone(func(z *Zone) bool { SortRegions(z.Regions) for _, region := range z.Regions { regions[region] = append(regions[region], z) } return false }) // bind first level regions and their zones for name, zones := range regions { m.syncRegions(name, zones...) } // and combine zones to produce larger regions for i := range m.Regions { r := &m.Regions[i] m.finishRegion(r) } m.sortRegions() return nil } func (m *Cluster) syncRegions(name string, zones ...*Zone) { for _, r := range m.Regions { if r.Name == name { // found r.m = m r.zones = zones return } } // new m.Regions = append(m.Regions, Region{ m: m, zones: zones, Name: name, }) } func (m *Cluster) finishRegion(r *Region) { if r.m != nil { // ready return } r.m = m sub := []string{} for _, name := range r.Regions { r2, ok := m.getRegion(name) if !ok { m.warn(nil).WithField("region", name).Print("unknown region") continue } sub = append(sub, r2.Name) r.zones = append(r.zones, r2.zones...) } r.Regions = sub } func (m *Cluster) getRegion(name string) (*Region, bool) { for i := range m.Regions { r := &m.Regions[i] if name == r.Name { m.finishRegion(r) return r, true } } return nil, false }