|
|
|
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_initial_members:")
|
|
|
|
for i, name := range err.Names {
|
|
|
|
if i != 0 {
|
|
|
|
_, _ = w.WriteRune(',')
|
|
|
|
}
|
|
|
|
_, _ = w.WriteString(name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (err *CephMissingMonitorError) writeAddrs(w *strings.Builder) {
|
|
|
|
if len(err.Addrs) > 0 {
|
|
|
|
_, _ = w.WriteString(" mon_host:")
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg != nil {
|
|
|
|
// store FSID
|
|
|
|
m.CephFSID = cfg.Global.FSID
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|