-
Notifications
You must be signed in to change notification settings - Fork 9
/
mgmt.go
142 lines (120 loc) · 3.24 KB
/
mgmt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package modules
import (
"context"
"github.com/tevino/abool"
"github.com/safing/portbase/log"
)
var (
moduleMgmtEnabled = abool.NewBool(false)
modulesChangeNotifyFn func(*Module)
)
// Enable enables the module. Only has an effect if module management
// is enabled.
func (m *Module) Enable() (changed bool) {
return m.enabled.SetToIf(false, true)
}
// Disable disables the module. Only has an effect if module management
// is enabled.
func (m *Module) Disable() (changed bool) {
return m.enabled.SetToIf(true, false)
}
// SetEnabled sets the module to the desired enabled state. Only has
// an effect if module management is enabled.
func (m *Module) SetEnabled(enable bool) (changed bool) {
if enable {
return m.Enable()
}
return m.Disable()
}
// Enabled returns whether or not the module is currently enabled.
func (m *Module) Enabled() bool {
return m.enabled.IsSet()
}
// EnabledAsDependency returns whether or not the module is currently
// enabled as a dependency.
func (m *Module) EnabledAsDependency() bool {
return m.enabledAsDependency.IsSet()
}
// EnableModuleManagement enables the module management functionality
// within modules. The supplied notify function will be called whenever
// the status of a module changes. The affected module will be in the
// parameter. You will need to manually enable modules, else nothing
// will start.
// EnableModuleManagement returns true if changeNotifyFn has been set
// and it has been called for the first time.
//
// Example:
//
// EnableModuleManagement(func(m *modules.Module) {
// // some module has changed ...
// // do what ever you like
//
// // Run the built-in module management
// modules.ManageModules()
// })
func EnableModuleManagement(changeNotifyFn func(*Module)) bool {
if moduleMgmtEnabled.SetToIf(false, true) {
modulesChangeNotifyFn = changeNotifyFn
return true
}
return false
}
// DisableModuleManagement disables module management and returns the module
// system to the default start/stop behavior.
func DisableModuleManagement() {
moduleMgmtEnabled.UnSet()
}
func (m *Module) notifyOfChange() {
if moduleMgmtEnabled.IsSet() && modulesChangeNotifyFn != nil {
m.StartWorker("notify of change", func(ctx context.Context) error {
modulesChangeNotifyFn(m)
return nil
})
}
}
// ManageModules triggers the module manager to react to recent changes of
// enabled modules.
func ManageModules() error {
// check if enabled
if !moduleMgmtEnabled.IsSet() {
return nil
}
// lock mgmt
mgmtLock.Lock()
defer mgmtLock.Unlock()
log.Info("modules: managing changes")
// build new dependency tree
buildEnabledTree()
// stop unneeded modules
lastErr := stopModules()
if lastErr != nil {
log.Warning(lastErr.Error())
}
// start needed modules
err := startModules()
if err != nil {
log.Warning(err.Error())
lastErr = err
}
log.Info("modules: finished managing")
return lastErr
}
func buildEnabledTree() {
// reset marked dependencies
for _, m := range modules {
m.enabledAsDependency.UnSet()
}
// mark dependencies
for _, m := range modules {
if m.enabled.IsSet() {
m.markDependencies()
}
}
}
func (m *Module) markDependencies() {
for _, dep := range m.depModules {
if dep.enabledAsDependency.SetToIf(false, true) {
dep.markDependencies()
}
}
}