github.com/safing/portbase@v0.19.5/modules/subsystems/subsystem.go (about) 1 package subsystems 2 3 import ( 4 "sync" 5 6 "github.com/safing/portbase/config" 7 "github.com/safing/portbase/database/record" 8 "github.com/safing/portbase/modules" 9 ) 10 11 // Subsystem describes a subset of modules that represent a part of a 12 // service or program to the user. Subsystems can be (de-)activated causing 13 // all related modules to be brought down or up. 14 type Subsystem struct { //nolint:maligned // not worth the effort 15 record.Base 16 sync.Mutex 17 // ID is a unique identifier for the subsystem. 18 ID string 19 // Name holds a human readable name of the subsystem. 20 Name string 21 // Description may holds an optional description of 22 // the subsystem's purpose. 23 Description string 24 // Modules contains all modules that are related to the subsystem. 25 // Note that this slice also contains a reference to the subsystem 26 // module itself. 27 Modules []*ModuleStatus 28 // FailureStatus is the worst failure status that is currently 29 // set in one of the subsystem's dependencies. 30 FailureStatus uint8 31 // ToggleOptionKey holds the key of the configuration option 32 // that is used to completely enable or disable this subsystem. 33 ToggleOptionKey string 34 // ExpertiseLevel defines the complexity of the subsystem and is 35 // copied from the subsystem's toggleOption. 36 ExpertiseLevel config.ExpertiseLevel 37 // ReleaseLevel defines the stability of the subsystem and is 38 // copied form the subsystem's toggleOption. 39 ReleaseLevel config.ReleaseLevel 40 // ConfigKeySpace defines the database key prefix that all 41 // options that belong to this subsystem have. Note that this 42 // value is mainly used to mark all related options with a 43 // config.SubsystemAnnotation. Options that are part of 44 // this subsystem but don't start with the correct prefix can 45 // still be marked by manually setting the appropriate annotation. 46 ConfigKeySpace string 47 48 module *modules.Module 49 toggleOption *config.Option 50 toggleValue config.BoolOption 51 } 52 53 // ModuleStatus describes the status of a module. 54 type ModuleStatus struct { 55 Name string 56 module *modules.Module 57 58 // status mgmt 59 Enabled bool 60 Status uint8 61 62 // failure status 63 FailureStatus uint8 64 FailureID string 65 FailureMsg string 66 } 67 68 func (sub *Subsystem) addDependencies(module *modules.Module, seen map[string]struct{}) { 69 for _, module := range module.Dependencies() { 70 if _, ok := seen[module.Name]; !ok { 71 seen[module.Name] = struct{}{} 72 73 sub.Modules = append(sub.Modules, statusFromModule(module)) 74 sub.addDependencies(module, seen) 75 } 76 } 77 } 78 79 func statusFromModule(module *modules.Module) *ModuleStatus { 80 status := &ModuleStatus{ 81 Name: module.Name, 82 module: module, 83 Enabled: module.Enabled() || module.EnabledAsDependency(), 84 Status: module.Status(), 85 } 86 status.FailureStatus, status.FailureID, status.FailureMsg = module.FailureStatus() 87 88 return status 89 } 90 91 func compareAndUpdateStatus(module *modules.Module, status *ModuleStatus) (changed bool) { 92 // check if enabled 93 enabled := module.Enabled() || module.EnabledAsDependency() 94 if status.Enabled != enabled { 95 status.Enabled = enabled 96 changed = true 97 } 98 99 // check status 100 statusLvl := module.Status() 101 if status.Status != statusLvl { 102 status.Status = statusLvl 103 changed = true 104 } 105 106 // check failure status 107 failureStatus, failureID, failureMsg := module.FailureStatus() 108 if status.FailureStatus != failureStatus || 109 status.FailureID != failureID { 110 111 status.FailureStatus = failureStatus 112 status.FailureID = failureID 113 status.FailureMsg = failureMsg 114 changed = true 115 } 116 117 return 118 } 119 120 func (sub *Subsystem) makeSummary() { 121 // find worst failing module 122 sub.FailureStatus = 0 123 for _, depStatus := range sub.Modules { 124 if depStatus.FailureStatus > sub.FailureStatus { 125 sub.FailureStatus = depStatus.FailureStatus 126 } 127 } 128 }