You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

219 lines
4.1 KiB

package cluster
import (
"bytes"
"fmt"
"io"
"sort"
"strings"
"git.jpi.io/amery/jpictl/pkg/rings"
)
// Env is a shell environment factory for this cluster
type Env struct {
ZoneIterator
RegionIterator
cephFSID string
export bool
}
// Env returns a shell environment factory
func (m *Cluster) Env(export bool) (*Env, error) {
fsid, err := m.GetCephFSID()
if err != nil {
return nil, err
}
env := &Env{
ZoneIterator: m,
RegionIterator: m,
cephFSID: fsid.String(),
export: export,
}
return env, nil
}
// Zones returns the list of Zone IDs
func (m *Env) Zones() []rings.ZoneID {
var zones []rings.ZoneID
m.ForEachZone(func(z *Zone) bool {
zones = append(zones, z.ID)
return false
})
return zones
}
// Regions returns the list of primary regions
func (m *Env) Regions() []string {
var regions []string
m.ForEachRegion(func(r *Region) bool {
if r.Cluster != nil {
regions = append(regions, r.Name)
}
return false
})
sort.Strings(regions)
return regions
}
// WriteTo generates environment variables for shell scripts
func (m *Env) WriteTo(w io.Writer) (int64, error) {
var buf bytes.Buffer
if m.cephFSID != "" {
m.writeEnvVar(&buf, m.cephFSID, "FSID")
}
m.writeEnvVar(&buf, genEnvStrings(m.Regions()), "REGIONS")
m.writeEnvVar(&buf, genEnvInts(m.Zones()), "ZONES")
m.ForEachZone(func(z *Zone) bool {
m.writeEnvZone(&buf, z)
return false
})
return buf.WriteTo(w)
}
func (m *Env) writeEnvZone(w io.Writer, z *Zone) {
zoneID := z.ID
// ZONE{zoneID}
m.writeEnvVar(w, genEnvZoneNodes(z), "ZONE%v", zoneID)
// ZONE{zoneID}_NAME
m.writeEnvVar(w, z.Name, "ZONE%v_%s", zoneID, "NAME")
// ZONE{zoneID}_GW
gateways, _ := z.GatewayIDs()
m.writeEnvVar(w, genEnvInts(gateways), "ZONE%v_%s", zoneID, "GW")
// ZONE{zoneID}_REGION
m.writeEnvVar(w, genEnvZoneRegion(z), "ZONE%v_%s", zoneID, "REGION")
// Ceph
monitors := z.GetCephMonitors()
// MON{zoneID}_NAME
m.writeEnvVar(w, genEnvZoneCephMonNames(monitors), "MON%v_%s", zoneID, "NAME")
// MON{zoneID}_IP
m.writeEnvVar(w, genEnvZoneCephMonIPs(monitors), "MON%v_%s", zoneID, "IP")
// MON{zoneID}_ID
m.writeEnvVar(w, genEnvZoneCephMonIDs(monitors), "MON%v_%s", zoneID, "ID")
}
func (m *Env) writeEnvVar(w io.Writer, value string, name string, args ...any) {
var prefix string
if m.export {
prefix = "export "
}
if len(args) > 0 {
name = fmt.Sprintf(name, args...)
}
if name != "" {
value = strings.TrimSpace(value)
if value == "" {
_, _ = fmt.Fprintf(w, "%s%s=\n", prefix, name)
} else {
_, _ = fmt.Fprintf(w, "%s%s=%q\n", prefix, name, value)
}
}
}
func genEnvInts[T ~int | ~uint](values []T) string {
var buf bytes.Buffer
for _, v := range values {
if buf.Len() > 0 {
_, _ = buf.WriteRune(' ')
}
_, _ = buf.WriteString(fmt.Sprintf("%v", v))
}
return buf.String()
}
func genEnvStrings(values []string) string {
return strings.Join(values, " ")
}
func genEnvZoneNodes(z *Zone) string {
if n := z.Len(); n > 0 {
s := make([]string, 0, n)
z.ForEachMachine(func(p *Machine) bool {
s = append(s, p.Name)
return false
})
return genEnvStrings(s)
}
return ""
}
func genEnvZoneRegion(z *Zone) string {
var region string
z.ForEachRegion(func(r *Region) bool {
if r.Cluster != nil {
region = r.Name
return true
}
return false
})
return region
}
func genEnvZoneCephMonNames(m Machines) string {
var buf strings.Builder
m.ForEachMachine(func(p *Machine) bool {
if buf.Len() > 0 {
_, _ = buf.WriteRune(' ')
}
_, _ = buf.WriteString(p.Name)
return false
})
return buf.String()
}
func genEnvZoneCephMonIPs(m Machines) string {
var buf strings.Builder
m.ForEachMachine(func(p *Machine) bool {
addr, _ := RingOneAddress(p.Zone(), p.ID)
if buf.Len() > 0 {
_, _ = buf.WriteRune(' ')
}
_, _ = buf.WriteString(addr.String())
return false
})
return buf.String()
}
func genEnvZoneCephMonIDs(m Machines) string {
var buf strings.Builder
m.ForEachMachine(func(p *Machine) bool {
if buf.Len() > 0 {
_, _ = buf.WriteRune(' ')
}
_, _ = fmt.Fprintf(&buf, "%v", p.ID)
return false
})
return buf.String()
}