Alejandro Mery
1 year ago
22 changed files with 338 additions and 304 deletions
@ -0,0 +1,77 @@ |
|||||||
|
// Package cluster contains information about the cluster
|
||||||
|
package cluster |
||||||
|
|
||||||
|
import ( |
||||||
|
"io/fs" |
||||||
|
|
||||||
|
"darvaza.org/resolver" |
||||||
|
"darvaza.org/slog" |
||||||
|
"github.com/gofrs/uuid/v5" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
_ MachineIterator = (*Cluster)(nil) |
||||||
|
_ ZoneIterator = (*Cluster)(nil) |
||||||
|
) |
||||||
|
|
||||||
|
// revive:disable:line-length-limit
|
||||||
|
|
||||||
|
// Cluster represents all zones in a cluster
|
||||||
|
type Cluster struct { |
||||||
|
dir fs.FS |
||||||
|
log slog.Logger |
||||||
|
resolver resolver.Resolver |
||||||
|
|
||||||
|
BaseDir string `json:"dir,omitempty" yaml:"dir,omitempty"` |
||||||
|
Name string `json:"name,omitempty" yaml:"name,omitempty"` |
||||||
|
Domain string `json:"domain,omitempty" yaml:"domain,omitempty"` |
||||||
|
|
||||||
|
CephFSID uuid.UUID `json:"ceph_fsid,omitempty" yaml:"ceph_fsid,omitempty"` |
||||||
|
Zones []*Zone `json:"zones,omitempty" yaml:"zones,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// revive:enable:line-length-limit
|
||||||
|
|
||||||
|
// ForEachMachine calls a function for each Machine in the cluster
|
||||||
|
// until instructed to terminate the loop
|
||||||
|
func (m *Cluster) ForEachMachine(fn func(*Machine) bool) { |
||||||
|
m.ForEachZone(func(z *Zone) bool { |
||||||
|
var term bool |
||||||
|
|
||||||
|
z.ForEachMachine(func(p *Machine) bool { |
||||||
|
term = fn(p) |
||||||
|
return term |
||||||
|
}) |
||||||
|
|
||||||
|
return term |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// ForEachZone calls a function for each Zone in the cluster
|
||||||
|
// until instructed to terminate the loop
|
||||||
|
func (m *Cluster) ForEachZone(fn func(*Zone) bool) { |
||||||
|
for _, p := range m.Zones { |
||||||
|
if fn(p) { |
||||||
|
// terminate
|
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// GetMachineByName looks for a machine with the specified
|
||||||
|
// name on any zone
|
||||||
|
func (m *Cluster) GetMachineByName(name string) (*Machine, bool) { |
||||||
|
var out *Machine |
||||||
|
|
||||||
|
if name != "" { |
||||||
|
m.ForEachMachine(func(p *Machine) bool { |
||||||
|
if p.Name == name { |
||||||
|
out = p |
||||||
|
} |
||||||
|
|
||||||
|
return out != nil |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
return out, out != nil |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package cluster |
||||||
|
|
||||||
|
import ( |
||||||
|
"darvaza.org/resolver" |
||||||
|
"darvaza.org/slog" |
||||||
|
"darvaza.org/slog/handlers/discard" |
||||||
|
) |
||||||
|
|
||||||
|
// DefaultLogger returns a logger that doesn't log anything
|
||||||
|
func DefaultLogger() slog.Logger { |
||||||
|
return discard.New() |
||||||
|
} |
||||||
|
|
||||||
|
// DefaultLookuper returns a [resolver.Lookuper] using Cloudflare's 1.1.1.1
|
||||||
|
func DefaultLookuper() resolver.Lookuper { |
||||||
|
return resolver.NewCloudflareLookuper() |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package zones |
package cluster |
||||||
|
|
||||||
import "errors" |
import "errors" |
||||||
|
|
@ -1,4 +1,4 @@ |
|||||||
package zones |
package cluster |
||||||
|
|
||||||
import ( |
import ( |
||||||
"bytes" |
"bytes" |
@ -1,4 +1,4 @@ |
|||||||
package zones |
package cluster |
||||||
|
|
||||||
import ( |
import ( |
||||||
"bytes" |
"bytes" |
@ -1,4 +1,4 @@ |
|||||||
package zones |
package cluster |
||||||
|
|
||||||
import ( |
import ( |
||||||
"context" |
"context" |
@ -0,0 +1,69 @@ |
|||||||
|
package cluster |
||||||
|
|
||||||
|
import "sort" |
||||||
|
|
||||||
|
var ( |
||||||
|
_ MachineIterator = Machines(nil) |
||||||
|
_ sort.Interface = Machines(nil) |
||||||
|
) |
||||||
|
|
||||||
|
// A MachineIterator is a set of Machines we can iterate on
|
||||||
|
type MachineIterator interface { |
||||||
|
ForEachMachine(func(*Machine) bool) |
||||||
|
} |
||||||
|
|
||||||
|
// Machines is a list of Machine objects
|
||||||
|
type Machines []*Machine |
||||||
|
|
||||||
|
// ForEachMachine calls a function for each Machine in the list
|
||||||
|
// until instructed to terminate the loop
|
||||||
|
func (m Machines) ForEachMachine(fn func(*Machine) bool) { |
||||||
|
for _, p := range m { |
||||||
|
if fn(p) { |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Len returns the number of machines in the list
|
||||||
|
func (m Machines) Len() int { |
||||||
|
return len(m) |
||||||
|
} |
||||||
|
|
||||||
|
// Less implements sort.Interface to sort the list
|
||||||
|
func (m Machines) Less(i, j int) bool { |
||||||
|
a, b := m[i], m[j] |
||||||
|
za, zb := a.Zone(), b.Zone() |
||||||
|
|
||||||
|
switch { |
||||||
|
case za == zb: |
||||||
|
return a.ID < b.ID |
||||||
|
default: |
||||||
|
return za < zb |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Swap implements sort.Interface to sort the list
|
||||||
|
func (m Machines) Swap(i, j int) { |
||||||
|
m[i], m[j] = m[j], m[i] |
||||||
|
} |
||||||
|
|
||||||
|
// FilterMachines produces a subset of the machines offered by the given
|
||||||
|
// iterator fulfilling a condition
|
||||||
|
func FilterMachines(m MachineIterator, cond func(*Machine) bool) (Machines, int) { |
||||||
|
var out []*Machine |
||||||
|
|
||||||
|
if cond == nil { |
||||||
|
// unconditional
|
||||||
|
cond = func(*Machine) bool { return true } |
||||||
|
} |
||||||
|
|
||||||
|
m.ForEachMachine(func(p *Machine) bool { |
||||||
|
if cond(p) { |
||||||
|
out = append(out, p) |
||||||
|
} |
||||||
|
return false |
||||||
|
}) |
||||||
|
|
||||||
|
return out, len(out) |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package zones |
package cluster |
||||||
|
|
||||||
import ( |
import ( |
||||||
"fmt" |
"fmt" |
@ -0,0 +1,68 @@ |
|||||||
|
package cluster |
||||||
|
|
||||||
|
import ( |
||||||
|
"io/fs" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
_ MachineIterator = (*Zone)(nil) |
||||||
|
) |
||||||
|
|
||||||
|
// A ZoneIterator is a set of Zones we can iterate on
|
||||||
|
type ZoneIterator interface { |
||||||
|
ForEachZone(func(*Zone) bool) |
||||||
|
} |
||||||
|
|
||||||
|
// A Zone is a set of machines in close proximity and strong
|
||||||
|
// affinity.
|
||||||
|
type Zone struct { |
||||||
|
zones *Cluster |
||||||
|
logger `json:"-" yaml:"-"` |
||||||
|
|
||||||
|
ID int |
||||||
|
Name string |
||||||
|
|
||||||
|
Machines |
||||||
|
} |
||||||
|
|
||||||
|
func (z *Zone) String() string { |
||||||
|
return z.Name |
||||||
|
} |
||||||
|
|
||||||
|
// SetGateway configures a machine to be the zone's ring0 gateway
|
||||||
|
func (z *Zone) SetGateway(gatewayID int, enabled bool) error { |
||||||
|
var err error |
||||||
|
var found bool |
||||||
|
|
||||||
|
z.ForEachMachine(func(p *Machine) bool { |
||||||
|
if p.ID == gatewayID { |
||||||
|
found = true |
||||||
|
err = p.SetGateway(enabled) |
||||||
|
|
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
}) |
||||||
|
|
||||||
|
switch { |
||||||
|
case err != nil: |
||||||
|
return err |
||||||
|
case !found: |
||||||
|
return fs.ErrNotExist |
||||||
|
default: |
||||||
|
return nil |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// GatewayIDs returns the list of IDs of machines that act as ring0 gateways
|
||||||
|
func (z *Zone) GatewayIDs() ([]int, int) { |
||||||
|
var out []int |
||||||
|
z.ForEachMachine(func(p *Machine) bool { |
||||||
|
if p.IsGateway() { |
||||||
|
out = append(out, p.ID) |
||||||
|
} |
||||||
|
return false |
||||||
|
}) |
||||||
|
|
||||||
|
return out, len(out) |
||||||
|
} |
@ -1,198 +0,0 @@ |
|||||||
// Package zones contains information about the cluster
|
|
||||||
package zones |
|
||||||
|
|
||||||
import ( |
|
||||||
"io/fs" |
|
||||||
"sort" |
|
||||||
|
|
||||||
"darvaza.org/resolver" |
|
||||||
"darvaza.org/slog" |
|
||||||
"github.com/gofrs/uuid/v5" |
|
||||||
) |
|
||||||
|
|
||||||
var ( |
|
||||||
_ MachineIterator = Machines(nil) |
|
||||||
_ sort.Interface = Machines(nil) |
|
||||||
|
|
||||||
_ MachineIterator = (*Zone)(nil) |
|
||||||
_ MachineIterator = (*Zones)(nil) |
|
||||||
_ ZoneIterator = (*Zones)(nil) |
|
||||||
) |
|
||||||
|
|
||||||
// A MachineIterator is a set of Machines we can iterate on
|
|
||||||
type MachineIterator interface { |
|
||||||
ForEachMachine(func(*Machine) bool) |
|
||||||
} |
|
||||||
|
|
||||||
// A ZoneIterator is a set of Zones we can iterate on
|
|
||||||
type ZoneIterator interface { |
|
||||||
ForEachZone(func(*Zone) bool) |
|
||||||
} |
|
||||||
|
|
||||||
// Machines is a list of Machine objects
|
|
||||||
type Machines []*Machine |
|
||||||
|
|
||||||
// ForEachMachine calls a function for each Machine in the list
|
|
||||||
// until instructed to terminate the loop
|
|
||||||
func (m Machines) ForEachMachine(fn func(*Machine) bool) { |
|
||||||
for _, p := range m { |
|
||||||
if fn(p) { |
|
||||||
return |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Len returns the number of machines in the list
|
|
||||||
func (m Machines) Len() int { |
|
||||||
return len(m) |
|
||||||
} |
|
||||||
|
|
||||||
// Less implements sort.Interface to sort the list
|
|
||||||
func (m Machines) Less(i, j int) bool { |
|
||||||
a, b := m[i], m[j] |
|
||||||
za, zb := a.Zone(), b.Zone() |
|
||||||
|
|
||||||
switch { |
|
||||||
case za == zb: |
|
||||||
return a.ID < b.ID |
|
||||||
default: |
|
||||||
return za < zb |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Swap implements sort.Interface to sort the list
|
|
||||||
func (m Machines) Swap(i, j int) { |
|
||||||
m[i], m[j] = m[j], m[i] |
|
||||||
} |
|
||||||
|
|
||||||
// FilterMachines produces a subset of the machines offered by the given
|
|
||||||
// iterator fulfilling a condition
|
|
||||||
func FilterMachines(m MachineIterator, cond func(*Machine) bool) (Machines, int) { |
|
||||||
var out []*Machine |
|
||||||
|
|
||||||
if cond == nil { |
|
||||||
// unconditional
|
|
||||||
cond = func(*Machine) bool { return true } |
|
||||||
} |
|
||||||
|
|
||||||
m.ForEachMachine(func(p *Machine) bool { |
|
||||||
if cond(p) { |
|
||||||
out = append(out, p) |
|
||||||
} |
|
||||||
return false |
|
||||||
}) |
|
||||||
|
|
||||||
return out, len(out) |
|
||||||
} |
|
||||||
|
|
||||||
// Zone represents one zone in a cluster
|
|
||||||
type Zone struct { |
|
||||||
zones *Zones |
|
||||||
logger `json:"-" yaml:"-"` |
|
||||||
|
|
||||||
ID int |
|
||||||
Name string |
|
||||||
|
|
||||||
Machines |
|
||||||
} |
|
||||||
|
|
||||||
func (z *Zone) String() string { |
|
||||||
return z.Name |
|
||||||
} |
|
||||||
|
|
||||||
// SetGateway configures a machine to be the zone's ring0 gateway
|
|
||||||
func (z *Zone) SetGateway(gatewayID int, enabled bool) error { |
|
||||||
var err error |
|
||||||
var found bool |
|
||||||
|
|
||||||
z.ForEachMachine(func(p *Machine) bool { |
|
||||||
if p.ID == gatewayID { |
|
||||||
found = true |
|
||||||
err = p.SetGateway(enabled) |
|
||||||
|
|
||||||
return true |
|
||||||
} |
|
||||||
return false |
|
||||||
}) |
|
||||||
|
|
||||||
switch { |
|
||||||
case err != nil: |
|
||||||
return err |
|
||||||
case !found: |
|
||||||
return fs.ErrNotExist |
|
||||||
default: |
|
||||||
return nil |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// GatewayIDs returns the list of IDs of machines that act as ring0 gateways
|
|
||||||
func (z *Zone) GatewayIDs() ([]int, int) { |
|
||||||
var out []int |
|
||||||
z.ForEachMachine(func(p *Machine) bool { |
|
||||||
if p.IsGateway() { |
|
||||||
out = append(out, p.ID) |
|
||||||
} |
|
||||||
return false |
|
||||||
}) |
|
||||||
|
|
||||||
return out, len(out) |
|
||||||
} |
|
||||||
|
|
||||||
// revive:disable:line-length-limit
|
|
||||||
|
|
||||||
// Zones represents all zones in a cluster
|
|
||||||
type Zones struct { |
|
||||||
dir fs.FS |
|
||||||
log slog.Logger |
|
||||||
resolver resolver.Resolver |
|
||||||
domain string |
|
||||||
|
|
||||||
CephFSID uuid.UUID `json:"ceph_fsid,omitempty" yaml:"ceph_fsid,omitempty"` |
|
||||||
Zones []*Zone |
|
||||||
} |
|
||||||
|
|
||||||
// revive:enable:line-length-limit
|
|
||||||
|
|
||||||
// ForEachMachine calls a function for each Machine in the cluster
|
|
||||||
// until instructed to terminate the loop
|
|
||||||
func (m *Zones) ForEachMachine(fn func(*Machine) bool) { |
|
||||||
m.ForEachZone(func(z *Zone) bool { |
|
||||||
var term bool |
|
||||||
|
|
||||||
z.ForEachMachine(func(p *Machine) bool { |
|
||||||
term = fn(p) |
|
||||||
return term |
|
||||||
}) |
|
||||||
|
|
||||||
return term |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
// ForEachZone calls a function for each Zone in the cluster
|
|
||||||
// until instructed to terminate the loop
|
|
||||||
func (m *Zones) ForEachZone(fn func(*Zone) bool) { |
|
||||||
for _, p := range m.Zones { |
|
||||||
if fn(p) { |
|
||||||
// terminate
|
|
||||||
return |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// GetMachineByName looks for a machine with the specified
|
|
||||||
// name on any zone
|
|
||||||
func (m *Zones) GetMachineByName(name string) (*Machine, bool) { |
|
||||||
var out *Machine |
|
||||||
|
|
||||||
if name != "" { |
|
||||||
m.ForEachMachine(func(p *Machine) bool { |
|
||||||
if p.Name == name { |
|
||||||
out = p |
|
||||||
} |
|
||||||
|
|
||||||
return out != nil |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
return out, out != nil |
|
||||||
} |
|
Loading…
Reference in new issue