Compare commits

...

4 Commits

Author SHA1 Message Date
amery c37bded53a env: set ceph monitors variables
they indicate the ceph monitors on the specified zone

* MON{zoneID}_NAME
* MON{zoneID}_ID
* MON{zoneID}_IP

Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-09-05 12:44:32 +00:00
amery abb3d3599d zones: extend scan to ensure every zone has a ceph monitor
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-09-05 12:44:32 +00:00
amery 3d4c4b9cff zones: set Machine.CephMonitor if its referenced as monitor on ceph.conf
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-09-05 12:44:32 +00:00
amery d2a9fcdfbc zones: introduce GenCephConfig()
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-09-05 12:44:19 +00:00
4 changed files with 258 additions and 0 deletions
+31
View File
@@ -2,6 +2,7 @@ package zones
import (
"bytes"
"net/netip"
"sort"
"darvaza.org/core"
@@ -30,6 +31,36 @@ func (m *Zones) GetCephConfig() (*ceph.Config, error) {
return ceph.NewConfigFromReader(r)
}
// GenCephConfig prepares a ceph.Config using the cluster information
func (m *Zones) GenCephConfig() (*ceph.Config, error) {
fsid, err := m.GetCephFSID()
if err != nil {
return nil, err
}
cfg := &ceph.Config{
Global: ceph.GlobalConfig{
FSID: fsid,
ClusterNetwork: netip.PrefixFrom(
netip.AddrFrom4([4]byte{10, 0, 0, 0}),
8,
),
},
}
m.ForEachZone(func(z *Zone) bool {
for _, p := range z.GetCephMonitors() {
addr, _ := RingOneAddress(z.ID, p.ID)
cfg.Global.Monitors = append(cfg.Global.Monitors, p.Name)
cfg.Global.MonitorsAddr = append(cfg.Global.MonitorsAddr, addr)
}
return false
})
return cfg, nil
}
// GetCephMonitors returns the set of Ceph monitors on
// the zone
func (z *Zone) GetCephMonitors() Machines {
+176
View File
@@ -0,0 +1,176 @@
package zones
import (
"net/netip"
"os"
"strings"
"darvaza.org/core"
"git.jpi.io/amery/jpictl/pkg/ceph"
)
// CephMissingMonitorError is an error that contains ceph
// monitors present in ceph.conf but not found on the cluster
type CephMissingMonitorError struct {
Names []string
Addrs []netip.Addr
}
func (err *CephMissingMonitorError) appendName(name string) {
err.Names = append(err.Names, name)
}
func (err *CephMissingMonitorError) appendAddr(addr netip.Addr) {
err.Addrs = append(err.Addrs, addr)
}
// OK tells if this instance actual shouldn't be treated as an error
func (err CephMissingMonitorError) OK() bool {
switch {
case len(err.Names) > 0:
return false
case len(err.Addrs) > 0:
return false
default:
return true
}
}
func (err CephMissingMonitorError) Error() string {
if !err.OK() {
var buf strings.Builder
_, _ = buf.WriteString("missing:")
err.writeNames(&buf)
err.writeAddrs(&buf)
return buf.String()
}
// no error
return ""
}
func (err *CephMissingMonitorError) writeNames(w *strings.Builder) {
if len(err.Names) > 0 {
_, _ = w.WriteString(" mon_host:")
for i, name := range err.Names {
if i != 0 {
_, _ = w.WriteRune(',')
}
_, _ = w.WriteString(name)
}
}
}
func (err *CephMissingMonitorError) writeAddrs(w *strings.Builder) {
_, _ = w.WriteString(" mon_initial_members:")
for i, addr := range err.Addrs {
if i != 0 {
_, _ = w.WriteRune(',')
}
_, _ = w.WriteString(addr.String())
}
}
// AsError returns nil if the instance is actually OK
func (err *CephMissingMonitorError) AsError() error {
if err == nil || err.OK() {
return nil
}
return err
}
type cephScanTODO struct {
names map[string]bool
addrs map[string]bool
}
func (todo *cephScanTODO) checkMachine(p *Machine) bool {
// on ceph all addresses are ring1
ring1, _ := RingOneAddress(p.Zone(), p.ID)
addr := ring1.String()
if _, found := todo.names[p.Name]; found {
// found on the TODO by name
todo.names[p.Name] = true
todo.addrs[addr] = true
return true
}
if _, found := todo.addrs[addr]; found {
// found on the TODO by address
todo.names[p.Name] = true
todo.addrs[addr] = true
return true
}
return false
}
func (todo *cephScanTODO) Missing() error {
var check CephMissingMonitorError
for name, found := range todo.names {
if !found {
check.appendName(name)
}
}
for addr, found := range todo.addrs {
if !found {
var a netip.Addr
// it wouldn't be on the map if it wasn't valid
_ = a.UnmarshalText([]byte(addr))
check.appendAddr(a)
}
}
return check.AsError()
}
func newCephScanTODO(cfg *ceph.Config) *cephScanTODO {
todo := &cephScanTODO{
names: make(map[string]bool),
addrs: make(map[string]bool),
}
for _, name := range cfg.Global.Monitors {
todo.names[name] = false
}
for _, addr := range cfg.Global.MonitorsAddr {
todo.addrs[addr.String()] = false
}
return todo
}
func (m *Zones) scanCephMonitors(_ *ScanOptions) error {
cfg, err := m.GetCephConfig()
switch {
case os.IsNotExist(err):
err = nil
case err != nil:
return err
}
// flag monitors based on config
todo := newCephScanTODO(cfg)
m.ForEachMachine(func(p *Machine) bool {
p.CephMonitor = todo.checkMachine(p)
return false
})
if err := todo.Missing(); err != nil {
return core.Wrap(err, "ceph")
}
// make sure every zone has one
m.ForEachZone(func(z *Zone) bool {
_ = z.GetCephMonitors()
return false
})
return nil
}
+50
View File
@@ -59,6 +59,15 @@ func (m *Env) writeEnvZone(w io.Writer, z *Zone) {
// ZONE{zoneID}_GW
gateways, _ := z.GatewayIDs()
m.writeEnvVarInts(w, gateways, "ZONE%v_%s", zoneID, "GW")
// 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) writeEnvVarInts(w io.Writer, value []int, name string, args ...any) {
@@ -111,3 +120,44 @@ func genEnvZoneNodes(z *Zone) string {
}
return ""
}
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()
}
+1
View File
@@ -12,6 +12,7 @@ func (m *Zones) scan(opts *ScanOptions) error {
m.scanZoneIDs,
m.scanSort,
m.scanGateways,
m.scanCephMonitors,
} {
if err := fn(opts); err != nil {
return err