Refactor admin socket setup (isolated config)

This commit is contained in:
Neil Alexander 2022-09-03 11:54:46 +01:00
parent 493208fb37
commit b1f61fb0a8
3 changed files with 70 additions and 58 deletions

View File

@ -359,6 +359,17 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
} }
} }
// Setup the admin socket.
{
options := []admin.SetupOption{
admin.ListenAddress(cfg.AdminListen),
}
n.admin, err = admin.New(n.core, logger, options...)
if err != nil {
panic(err)
}
}
// Setup the multicast module. // Setup the multicast module.
{ {
options := []multicast.SetupOption{} options := []multicast.SetupOption{}
@ -374,25 +385,13 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
if n.admin != nil {
n.multicast.SetupAdminHandlers(n.admin)
}
} }
// Register the session firewall gatekeeper function
// Allocate our modules
n.admin = &admin.AdminSocket{}
n.tuntap = &tuntap.TunAdapter{}
// Start the admin socket
if err := n.admin.Init(n.core, cfg, logger, nil); err != nil {
logger.Errorln("An error occurred initialising admin socket:", err)
} else if err := n.admin.Start(); err != nil {
logger.Errorln("An error occurred starting admin socket:", err)
}
n.admin.SetupAdminHandlers()
// Start the multicast interface
if n.multicast, err = multicast.New(n.core, logger, nil); err != nil {
logger.Errorln("An error occurred initialising multicast:", err)
}
n.multicast.SetupAdminHandlers(n.admin)
// Start the TUN/TAP interface // Start the TUN/TAP interface
n.tuntap = &tuntap.TunAdapter{}
rwc := ipv6rwc.NewReadWriteCloser(n.core) rwc := ipv6rwc.NewReadWriteCloser(n.core)
if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil { if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil {
logger.Errorln("An error occurred initialising TUN/TAP:", err) logger.Errorln("An error occurred initialising TUN/TAP:", err)

View File

@ -12,21 +12,21 @@ import (
"strings" "strings"
"time" "time"
"github.com/gologme/log"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/core" "github.com/yggdrasil-network/yggdrasil-go/src/core"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
) )
// TODO: Add authentication // TODO: Add authentication
type AdminSocket struct { type AdminSocket struct {
core *core.Core core *core.Core
log *log.Logger log util.Logger
listenaddr string listener net.Listener
listener net.Listener handlers map[string]handler
handlers map[string]handler done chan struct{}
done chan struct{} config struct {
listenaddr ListenAddress
}
} }
type AdminSocketRequest struct { type AdminSocketRequest struct {
@ -69,15 +69,18 @@ func (a *AdminSocket) AddHandler(name string, args []string, handlerfunc core.Ad
} }
// Init runs the initial admin setup. // Init runs the initial admin setup.
func (a *AdminSocket) Init(c *core.Core, nc *config.NodeConfig, log *log.Logger, options interface{}) error { func New(c *core.Core, log util.Logger, opts ...SetupOption) (*AdminSocket, error) {
a.core = c a := &AdminSocket{
a.log = log core: c,
a.handlers = make(map[string]handler) log: log,
nc.RLock() handlers: make(map[string]handler),
a.listenaddr = nc.AdminListen }
nc.RUnlock() for _, opt := range opts {
a.done = make(chan struct{}) a._applyOption(opt)
close(a.done) // Start in a done / not-started state }
if a.config.listenaddr == "none" || a.config.listenaddr == "" {
return nil, nil
}
_ = a.AddHandler("list", []string{}, func(_ json.RawMessage) (interface{}, error) { _ = a.AddHandler("list", []string{}, func(_ json.RawMessage) (interface{}, error) {
res := &ListResponse{} res := &ListResponse{}
for name, handler := range a.handlers { for name, handler := range a.handlers {
@ -91,7 +94,9 @@ func (a *AdminSocket) Init(c *core.Core, nc *config.NodeConfig, log *log.Logger,
}) })
return res, nil return res, nil
}) })
return a.core.SetAdmin(a) a.done = make(chan struct{})
go a.listen()
return a, a.core.SetAdmin(a)
} }
func (a *AdminSocket) SetupAdminHandlers() { func (a *AdminSocket) SetupAdminHandlers() {
@ -156,15 +161,6 @@ func (a *AdminSocket) SetupAdminHandlers() {
//_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) //_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler)
} }
// Start runs the admin API socket to listen for / respond to admin API calls.
func (a *AdminSocket) Start() error {
if a.listenaddr != "none" && a.listenaddr != "" {
a.done = make(chan struct{})
go a.listen()
}
return nil
}
// IsStarted returns true if the module has been started. // IsStarted returns true if the module has been started.
func (a *AdminSocket) IsStarted() bool { func (a *AdminSocket) IsStarted() bool {
select { select {
@ -192,31 +188,32 @@ func (a *AdminSocket) Stop() error {
// listen is run by start and manages API connections. // listen is run by start and manages API connections.
func (a *AdminSocket) listen() { func (a *AdminSocket) listen() {
u, err := url.Parse(a.listenaddr) listenaddr := string(a.config.listenaddr)
u, err := url.Parse(listenaddr)
if err == nil { if err == nil {
switch strings.ToLower(u.Scheme) { switch strings.ToLower(u.Scheme) {
case "unix": case "unix":
if _, err := os.Stat(a.listenaddr[7:]); err == nil { if _, err := os.Stat(listenaddr[7:]); err == nil {
a.log.Debugln("Admin socket", a.listenaddr[7:], "already exists, trying to clean up") a.log.Debugln("Admin socket", listenaddr[7:], "already exists, trying to clean up")
if _, err := net.DialTimeout("unix", a.listenaddr[7:], time.Second*2); err == nil || err.(net.Error).Timeout() { if _, err := net.DialTimeout("unix", listenaddr[7:], time.Second*2); err == nil || err.(net.Error).Timeout() {
a.log.Errorln("Admin socket", a.listenaddr[7:], "already exists and is in use by another process") a.log.Errorln("Admin socket", listenaddr[7:], "already exists and is in use by another process")
os.Exit(1) os.Exit(1)
} else { } else {
if err := os.Remove(a.listenaddr[7:]); err == nil { if err := os.Remove(listenaddr[7:]); err == nil {
a.log.Debugln(a.listenaddr[7:], "was cleaned up") a.log.Debugln(listenaddr[7:], "was cleaned up")
} else { } else {
a.log.Errorln(a.listenaddr[7:], "already exists and was not cleaned up:", err) a.log.Errorln(listenaddr[7:], "already exists and was not cleaned up:", err)
os.Exit(1) os.Exit(1)
} }
} }
} }
a.listener, err = net.Listen("unix", a.listenaddr[7:]) a.listener, err = net.Listen("unix", listenaddr[7:])
if err == nil { if err == nil {
switch a.listenaddr[7:8] { switch listenaddr[7:8] {
case "@": // maybe abstract namespace case "@": // maybe abstract namespace
default: default:
if err := os.Chmod(a.listenaddr[7:], 0660); err != nil { if err := os.Chmod(listenaddr[7:], 0660); err != nil {
a.log.Warnln("WARNING:", a.listenaddr[:7], "may have unsafe permissions!") a.log.Warnln("WARNING:", listenaddr[:7], "may have unsafe permissions!")
} }
} }
} }
@ -224,10 +221,10 @@ func (a *AdminSocket) listen() {
a.listener, err = net.Listen("tcp", u.Host) a.listener, err = net.Listen("tcp", u.Host)
default: default:
// err = errors.New(fmt.Sprint("protocol not supported: ", u.Scheme)) // err = errors.New(fmt.Sprint("protocol not supported: ", u.Scheme))
a.listener, err = net.Listen("tcp", a.listenaddr) a.listener, err = net.Listen("tcp", listenaddr)
} }
} else { } else {
a.listener, err = net.Listen("tcp", a.listenaddr) a.listener, err = net.Listen("tcp", listenaddr)
} }
if err != nil { if err != nil {
a.log.Errorf("Admin socket failed to listen: %v", err) a.log.Errorf("Admin socket failed to listen: %v", err)

16
src/admin/options.go Normal file
View File

@ -0,0 +1,16 @@
package admin
func (c *AdminSocket) _applyOption(opt SetupOption) {
switch v := opt.(type) {
case ListenAddress:
c.config.listenaddr = v
}
}
type SetupOption interface {
isSetupOption()
}
type ListenAddress string
func (a ListenAddress) isSetupOption() {}