mirror of
https://github.com/safing/portbase
synced 2025-09-04 11:40:23 +00:00
Improve modules and subsystems packages
This commit is contained in:
parent
bff3f5a1dd
commit
8d05b0b7c4
6 changed files with 107 additions and 17 deletions
|
@ -1,14 +1,19 @@
|
||||||
package modules
|
package modules
|
||||||
|
|
||||||
import "flag"
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// HelpFlag triggers printing flag.Usage. It's exported for custom help handling.
|
// HelpFlag triggers printing flag.Usage. It's exported for custom help handling.
|
||||||
HelpFlag bool
|
HelpFlag bool
|
||||||
|
printGraphFlag bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.BoolVar(&HelpFlag, "help", false, "print help")
|
flag.BoolVar(&HelpFlag, "help", false, "print help")
|
||||||
|
flag.BoolVar(&printGraphFlag, "print-module-graph", false, "print the module dependency graph")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFlags() error {
|
func parseFlags() error {
|
||||||
|
@ -20,5 +25,36 @@ func parseFlags() error {
|
||||||
return ErrCleanExit
|
return ErrCleanExit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if printGraphFlag {
|
||||||
|
printGraph()
|
||||||
|
return ErrCleanExit
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printGraph() {
|
||||||
|
// mark roots
|
||||||
|
for _, module := range modules {
|
||||||
|
if len(module.depReverse) == 0 {
|
||||||
|
// is root, dont print deps in dep tree
|
||||||
|
module.stopFlag.Set()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// print
|
||||||
|
for _, module := range modules {
|
||||||
|
if module.stopFlag.IsSet() {
|
||||||
|
// print from root
|
||||||
|
printModuleGraph("", module, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printModuleGraph(prefix string, module *Module, root bool) {
|
||||||
|
fmt.Printf("%s├── %s\n", prefix, module.Name)
|
||||||
|
if root || !module.stopFlag.IsSet() {
|
||||||
|
for _, dep := range module.Dependencies() {
|
||||||
|
printModuleGraph(fmt.Sprintf("│ %s", prefix), dep, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -48,7 +48,9 @@ func Start() error {
|
||||||
// parse flags
|
// parse flags
|
||||||
err = parseFlags()
|
err = parseFlags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "CRITICAL ERROR: failed to parse flags: %s\n", err)
|
if err != ErrCleanExit {
|
||||||
|
fmt.Fprintf(os.Stderr, "CRITICAL ERROR: failed to parse flags: %s\n", err)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +94,11 @@ func Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// complete startup
|
// complete startup
|
||||||
log.Infof("modules: started %d modules", len(modules))
|
if moduleMgmtEnabled.IsSet() {
|
||||||
|
log.Info("modules: initiated subsystems manager")
|
||||||
|
} else {
|
||||||
|
log.Infof("modules: started %d modules", len(modules))
|
||||||
|
}
|
||||||
|
|
||||||
go taskQueueHandler()
|
go taskQueueHandler()
|
||||||
go taskScheduleHandler()
|
go taskScheduleHandler()
|
||||||
|
|
|
@ -16,6 +16,11 @@ var (
|
||||||
shutdownCompleteSignal = make(chan struct{})
|
shutdownCompleteSignal = make(chan struct{})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IsShuttingDown returns whether the global shutdown is in progress.
|
||||||
|
func IsShuttingDown() bool {
|
||||||
|
return shutdownFlag.IsSet()
|
||||||
|
}
|
||||||
|
|
||||||
// ShuttingDown returns a channel read on the global shutdown signal.
|
// ShuttingDown returns a channel read on the global shutdown signal.
|
||||||
func ShuttingDown() <-chan struct{} {
|
func ShuttingDown() <-chan struct{} {
|
||||||
return shutdownSignal
|
return shutdownSignal
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package subsystems
|
package subsystems
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/safing/portbase/database"
|
"github.com/safing/portbase/database"
|
||||||
|
@ -14,7 +17,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
module *modules.Module
|
module *modules.Module
|
||||||
|
printGraphFlag bool
|
||||||
|
|
||||||
databaseKeySpace string
|
databaseKeySpace string
|
||||||
db = database.NewInterface(nil)
|
db = database.NewInterface(nil)
|
||||||
|
@ -30,9 +34,16 @@ func init() {
|
||||||
|
|
||||||
// register event for changes in the subsystem
|
// register event for changes in the subsystem
|
||||||
module.RegisterEvent(subsystemsStatusChange)
|
module.RegisterEvent(subsystemsStatusChange)
|
||||||
|
|
||||||
|
flag.BoolVar(&printGraphFlag, "print-subsystem-graph", false, "print the subsystem module dependency graph")
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() error {
|
func prep() error {
|
||||||
|
if printGraphFlag {
|
||||||
|
printGraph()
|
||||||
|
return modules.ErrCleanExit
|
||||||
|
}
|
||||||
|
|
||||||
return module.RegisterEventHook("config", configChangeEvent, "control subsystems", handleConfigChanges)
|
return module.RegisterEventHook("config", configChangeEvent, "control subsystems", handleConfigChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +65,10 @@ func start() error {
|
||||||
subsystemsLock.Unlock()
|
subsystemsLock.Unlock()
|
||||||
|
|
||||||
// apply config
|
// apply config
|
||||||
return handleConfigChanges(module.Ctx, nil)
|
module.StartWorker("initial subsystem configuration", func(ctx context.Context) error {
|
||||||
|
return handleConfigChanges(module.Ctx, nil)
|
||||||
|
})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sub *Subsystem) addDependencies(module *modules.Module, seen map[string]struct{}) {
|
func (sub *Subsystem) addDependencies(module *modules.Module, seen map[string]struct{}) {
|
||||||
|
@ -81,3 +95,23 @@ func SetDatabaseKeySpace(keySpace string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printGraph() {
|
||||||
|
// mark roots
|
||||||
|
for _, sub := range subsystems {
|
||||||
|
sub.module.Enable() // mark as tree root
|
||||||
|
}
|
||||||
|
// print
|
||||||
|
for _, sub := range subsystems {
|
||||||
|
printModuleGraph("", sub.module, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printModuleGraph(prefix string, module *modules.Module, root bool) {
|
||||||
|
fmt.Printf("%s├── %s\n", prefix, module.Name)
|
||||||
|
if root || !module.Enabled() {
|
||||||
|
for _, dep := range module.Dependencies() {
|
||||||
|
printModuleGraph(fmt.Sprintf("│ %s", prefix), dep, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ type Subsystem struct { //nolint:maligned // not worth the effort
|
||||||
record.Base
|
record.Base
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
|
ID string
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
module *modules.Module
|
module *modules.Module
|
||||||
|
@ -22,7 +23,7 @@ type Subsystem struct { //nolint:maligned // not worth the effort
|
||||||
Dependencies []*ModuleStatus
|
Dependencies []*ModuleStatus
|
||||||
FailureStatus uint8
|
FailureStatus uint8
|
||||||
|
|
||||||
ToggleOptionKey string // empty == forced on
|
ToggleOptionKey string
|
||||||
toggleOption *config.Option
|
toggleOption *config.Option
|
||||||
toggleValue func() bool
|
toggleValue func() bool
|
||||||
ExpertiseLevel uint8 // copied from toggleOption
|
ExpertiseLevel uint8 // copied from toggleOption
|
||||||
|
@ -49,7 +50,9 @@ type ModuleStatus struct {
|
||||||
// Save saves the Subsystem Status to the database.
|
// Save saves the Subsystem Status to the database.
|
||||||
func (sub *Subsystem) Save() {
|
func (sub *Subsystem) Save() {
|
||||||
if databaseKeySpace != "" {
|
if databaseKeySpace != "" {
|
||||||
// sub.SetKey() // FIXME
|
if !sub.KeyIsSet() {
|
||||||
|
sub.SetKey(databaseKeySpace + sub.ID)
|
||||||
|
}
|
||||||
err := db.Put(sub)
|
err := db.Put(sub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("subsystems: could not save subsystem status to database: %s", err)
|
log.Errorf("subsystems: could not save subsystem status to database: %s", err)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package subsystems
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -22,25 +21,26 @@ var (
|
||||||
handlingConfigChanges = abool.New()
|
handlingConfigChanges = abool.New()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Register registers a new subsystem. The given option must be a bool option. Should be called in the module's prep function. The config option must not yet be registered and will be registered for you.
|
// Register registers a new subsystem. The given option must be a bool option. Should be called in init() directly after the modules.Register() function. The config option must not yet be registered and will be registered for you. Pass a nil option to force enable.
|
||||||
func Register(name, description string, module *modules.Module, configKeySpace string, option *config.Option) error {
|
func Register(id, name, description string, module *modules.Module, configKeySpace string, option *config.Option) {
|
||||||
// lock slice and map
|
// lock slice and map
|
||||||
subsystemsLock.Lock()
|
subsystemsLock.Lock()
|
||||||
defer subsystemsLock.Unlock()
|
defer subsystemsLock.Unlock()
|
||||||
|
|
||||||
// check if registration is closed
|
// check if registration is closed
|
||||||
if subsystemsLocked.IsSet() {
|
if subsystemsLocked.IsSet() {
|
||||||
return errors.New("subsystems can only be registered in prep phase")
|
panic("subsystems can only be registered in prep phase or earlier")
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if already registered
|
// check if already registered
|
||||||
_, ok := subsystemsMap[name]
|
_, ok := subsystemsMap[name]
|
||||||
if ok {
|
if ok {
|
||||||
return fmt.Errorf(`subsystem "%s" already registered`, name)
|
panic(fmt.Sprintf(`subsystem "%s" already registered`, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new
|
// create new
|
||||||
new := &Subsystem{
|
new := &Subsystem{
|
||||||
|
ID: id,
|
||||||
Name: name,
|
Name: name,
|
||||||
Description: description,
|
Description: description,
|
||||||
module: module,
|
module: module,
|
||||||
|
@ -60,16 +60,17 @@ func Register(name, description string, module *modules.Module, configKeySpace s
|
||||||
if option != nil {
|
if option != nil {
|
||||||
err := config.Register(option)
|
err := config.Register(option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to register config: %s", err)
|
panic(fmt.Sprintf("failed to register config: %s", err))
|
||||||
}
|
}
|
||||||
|
new.toggleValue = config.GetAsBool(new.ToggleOptionKey, false)
|
||||||
|
} else {
|
||||||
|
// force enabled
|
||||||
|
new.toggleValue = func() bool { return true }
|
||||||
}
|
}
|
||||||
new.toggleValue = config.GetAsBool(new.ToggleOptionKey, false)
|
|
||||||
|
|
||||||
// add to lists
|
// add to lists
|
||||||
subsystemsMap[name] = new
|
subsystemsMap[name] = new
|
||||||
subsystems = append(subsystems, new)
|
subsystems = append(subsystems, new)
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleModuleChanges(m *modules.Module) {
|
func handleModuleChanges(m *modules.Module) {
|
||||||
|
@ -78,6 +79,11 @@ func handleModuleChanges(m *modules.Module) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if shutting down
|
||||||
|
if modules.IsShuttingDown() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// find module status
|
// find module status
|
||||||
var moduleSubsystem *Subsystem
|
var moduleSubsystem *Subsystem
|
||||||
var moduleStatus *ModuleStatus
|
var moduleStatus *ModuleStatus
|
||||||
|
|
Loading…
Add table
Reference in a new issue