Browse Source

ceph: add NewConfigFromReader() and initial ceph.conf parser

Signed-off-by: Alejandro Mery <amery@jpi.io>
pull/9/head
Alejandro Mery 1 year ago
parent
commit
94011a3a03
  1. 2
      go.mod
  2. 4
      go.sum
  3. 2
      pkg/ceph/ceph.go
  4. 38
      pkg/ceph/config.go
  5. 110
      pkg/ceph/config_parser.go

2
go.mod

@ -3,6 +3,7 @@ module git.jpi.io/amery/jpictl
go 1.19 go 1.19
require ( require (
asciigoat.org/ini v0.2.5
darvaza.org/core v0.9.8 darvaza.org/core v0.9.8
darvaza.org/resolver v0.5.4 darvaza.org/resolver v0.5.4
darvaza.org/sidecar v0.0.2 darvaza.org/sidecar v0.0.2
@ -18,6 +19,7 @@ require (
) )
require ( require (
asciigoat.org/core v0.3.9 // indirect
darvaza.org/slog/handlers/filter v0.4.5 // indirect darvaza.org/slog/handlers/filter v0.4.5 // indirect
darvaza.org/slog/handlers/zerolog v0.4.5 // indirect darvaza.org/slog/handlers/zerolog v0.4.5 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect github.com/BurntSushi/toml v1.3.2 // indirect

4
go.sum

@ -1,3 +1,7 @@
asciigoat.org/core v0.3.9 h1:hgDDz4ecm3ZvehX++m8A/IzAt+B5oDPiRtxatzfUHPQ=
asciigoat.org/core v0.3.9/go.mod h1:CAaHwyw8MpAq4a1MYtN2dxJrsK+hmIdW50OndaQZYPI=
asciigoat.org/ini v0.2.5 h1:4gRIp9rU+XQt8+HMqZO5R7GavMv9Yl2+N+je6djDIAE=
asciigoat.org/ini v0.2.5/go.mod h1:gmXzJ9XFqf1NLk5nQkj04USQ4tMtdRJHNQX6vp3DzjU=
darvaza.org/core v0.9.8 h1:luLxgfUc2pzuusYPo/Z/dC/qr9XZPKpSQw8/kS7zNUM= darvaza.org/core v0.9.8 h1:luLxgfUc2pzuusYPo/Z/dC/qr9XZPKpSQw8/kS7zNUM=
darvaza.org/core v0.9.8/go.mod h1:Dbme64naxeshQfxcVJX9ZT7AiGyIY8kldfuELVtf8mw= darvaza.org/core v0.9.8/go.mod h1:Dbme64naxeshQfxcVJX9ZT7AiGyIY8kldfuELVtf8mw=
darvaza.org/resolver v0.5.4 h1:dlSBNV14yYsp7Kg7ipwYOMNsLbrpeXa8Z0HBTa0Ryxs= darvaza.org/resolver v0.5.4 h1:dlSBNV14yYsp7Kg7ipwYOMNsLbrpeXa8Z0HBTa0Ryxs=

2
pkg/ceph/ceph.go

@ -0,0 +1,2 @@
// Package ceph deals with ceph config
package ceph

38
pkg/ceph/config.go

@ -0,0 +1,38 @@
package ceph
import (
"io"
"net/netip"
"github.com/gofrs/uuid/v5"
"asciigoat.org/ini/basic"
)
// Config represents a ceph.conf file
type Config struct {
Global GlobalConfig `ini:"global"`
}
// GlobalConfig represents the [global] section of a ceph.conf file
type GlobalConfig struct {
FSID uuid.UUID `ini:"fsid"`
Monitors []string `ini:"mon_initial_members,comma"`
MonitorsAddr []netip.Addr `ini:"mon_host,comma"`
ClusterNetwork netip.Prefix `ini:"cluster_network"`
}
// NewConfigFromReader parses the ceph.conf file
func NewConfigFromReader(r io.Reader) (*Config, error) {
doc, err := basic.Decode(r)
if err != nil {
return nil, err
}
cfg, err := newConfigFromDocument(doc)
if err != nil {
return nil, err
}
return cfg, nil
}

110
pkg/ceph/config_parser.go

@ -0,0 +1,110 @@
package ceph
import (
"io/fs"
"net/netip"
"asciigoat.org/ini/basic"
"asciigoat.org/ini/parser"
"darvaza.org/core"
)
var sectionMap = map[string]func(*Config, *basic.Section) error{
"global": loadGlobalConfSection,
}
func loadConfSection(out *Config, src *basic.Section) error {
h, ok := sectionMap[src.Key]
if !ok {
return core.Wrapf(fs.ErrInvalid, "unknown section %q", src.Key)
}
return h(out, src)
}
func loadGlobalConfSection(out *Config, src *basic.Section) error {
var cfg GlobalConfig
for _, field := range src.Fields {
if err := loadGlobalConfField(&cfg, field); err != nil {
return core.Wrap(err, "global")
}
}
out.Global = cfg
return nil
}
// revive:disable:cyclomatic
// revive:disable:cognitive-complexity
func loadGlobalConfField(cfg *GlobalConfig, field basic.Field) error {
// revive:enable:cyclomatic
// revive:enable:cognitive-complexity
// TODO: refactor when asciigoat's ini parser learns to do reflection
switch field.Key {
case "fsid":
if !core.IsZero(cfg.FSID) {
return core.Wrapf(fs.ErrInvalid, "duplicate field %q", field.Key)
}
err := cfg.FSID.UnmarshalText([]byte(field.Value))
switch {
case err != nil:
return core.Wrap(err, field.Key)
default:
return nil
}
case "mon_host":
entries, _ := parser.SplitCommaArray(field.Value)
for _, s := range entries {
var addr netip.Addr
if err := addr.UnmarshalText([]byte(s)); err != nil {
return core.Wrap(err, field.Key)
}
cfg.MonitorsAddr = append(cfg.MonitorsAddr, addr)
}
return nil
case "mon_initial_members":
entries, _ := parser.SplitCommaArray(field.Value)
cfg.Monitors = append(cfg.Monitors, entries...)
return nil
case "cluster_network":
if !core.IsZero(cfg.ClusterNetwork) {
err := core.Wrap(fs.ErrInvalid, "fields before the first section")
return err
}
err := cfg.ClusterNetwork.UnmarshalText([]byte(field.Value))
switch {
case err != nil:
return core.Wrap(err, field.Key)
default:
return nil
}
}
return nil
}
func newConfigFromDocument(doc *basic.Document) (*Config, error) {
var out Config
if len(doc.Global) > 0 {
err := core.Wrap(fs.ErrInvalid, "fields before the first section")
return nil, err
}
for i := range doc.Sections {
src := &doc.Sections[i]
if err := loadConfSection(&out, src); err != nil {
return nil, err
}
}
return &out, nil
}
Loading…
Cancel
Save