Alejandro Mery
1 year ago
2 changed files with 172 additions and 0 deletions
@ -0,0 +1,171 @@
|
||||
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") |
||||
} |
||||
|
||||
return nil |
||||
} |
Loading…
Reference in new issue