Skip to content

Commit

Permalink
[addon-operator] add module reregister
Browse files Browse the repository at this point in the history
Signed-off-by: Mikhail Scherba <[email protected]>
  • Loading branch information
miklezzzz committed Dec 11, 2023
1 parent a9a25d8 commit 8bf7f03
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 42 deletions.
1 change: 1 addition & 0 deletions pkg/addon-operator/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func (op *AddonOperator) SetupModuleManager(modulesDir string, globalHooksDir st
HelmResourcesManager: op.HelmResourcesManager,
MetricStorage: op.engine.MetricStorage,
HookMetricStorage: op.engine.HookMetricStorage,
TaskQueue: op.engine.TaskQueues,
}

cfg := module_manager.ModuleManagerConfig{
Expand Down
117 changes: 75 additions & 42 deletions pkg/module_manager/loader/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,80 @@ func NewFileSystemLoader(moduleDirs string, vv *validation.ValuesValidator) *Fil
}
}

func (fl *FileSystemLoader) getBasicModule(definition moduleDefinition, commonStaticValues utils.Values) (*modules.BasicModule, error) {
err := validateModuleName(definition.Name)
if err != nil {
return nil, err
}

valuesModuleName := utils.ModuleNameToValuesKey(definition.Name)
initialValues := utils.Values{valuesModuleName: map[string]interface{}{}}
// build initial values
// 1. from common static values
if commonStaticValues.HasKey(valuesModuleName) {
initialValues = utils.MergeValues(initialValues, commonStaticValues)
}

// 2. from module static values
moduleStaticValues, err := utils.LoadValuesFileFromDir(definition.Path)
if err != nil {
return nil, err
}

if moduleStaticValues != nil {
initialValues = utils.MergeValues(initialValues, moduleStaticValues)
}

// 3. from openapi defaults

cb, vb, err := fl.readOpenAPIFiles(filepath.Join(definition.Path, "openapi"))
if err != nil {
return nil, err
}

if cb != nil && vb != nil {
err = fl.valuesValidator.SchemaStorage.AddModuleValuesSchemas(valuesModuleName, cb, vb)
if err != nil {
return nil, err
}
}

//
moduleValues, ok := initialValues[valuesModuleName].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("expect map[string]interface{} in module values")
}

return modules.NewBasicModule(definition.Name, definition.Path, definition.Order, moduleValues, fl.valuesValidator), nil
}

// read single directory and return BasicModule for loading
func (fl *FileSystemLoader) ReloadModule(moduleName, modulePath string) (*modules.BasicModule, error) {

Check failure on line 80 in pkg/module_manager/loader/fs/fs.go

View workflow job for this annotation

GitHub Actions / Run Go linters

unused-parameter: parameter 'moduleName' seems to be unused, consider removing or renaming it as _ (revive)
commonStaticValues, err := utils.LoadValuesFileFromDir(modulePath)
if err != nil {
return nil, err
}

modDef, err := fl.findModulesInDir(modulePath)
if err != nil {
return nil, err
}

switch len(modDef) {
case 0:
return nil, fmt.Errorf("couldn't find addon-operator module definition in %s", modulePath)
case 1:
bm, err := fl.getBasicModule(modDef[0], commonStaticValues)
if err != nil {
return nil, err
}

return bm, nil
default:
return nil, fmt.Errorf("more than one addon-operator module definition found in %s", modulePath)
}
}

func (fl *FileSystemLoader) LoadModules() ([]*modules.BasicModule, error) {
result := make([]*modules.BasicModule, 0)

Expand All @@ -44,51 +118,10 @@ func (fl *FileSystemLoader) LoadModules() ([]*modules.BasicModule, error) {
}

for _, module := range modDefs {
err = validateModuleName(module.Name)
if err != nil {
return nil, err
}

valuesModuleName := utils.ModuleNameToValuesKey(module.Name)
initialValues := utils.Values{valuesModuleName: map[string]interface{}{}}
// build initial values
// 1. from common static values
if commonStaticValues.HasKey(valuesModuleName) {
initialValues = utils.MergeValues(initialValues, commonStaticValues)
}

// 2. from module static values
moduleStaticValues, err := utils.LoadValuesFileFromDir(module.Path)
bm, err := fl.getBasicModule(module, commonStaticValues)
if err != nil {
return nil, err
}

if moduleStaticValues != nil {
initialValues = utils.MergeValues(initialValues, moduleStaticValues)
}

// 3. from openapi defaults

cb, vb, err := fl.readOpenAPIFiles(filepath.Join(module.Path, "openapi"))
if err != nil {
return nil, err
}

if cb != nil && vb != nil {
err = fl.valuesValidator.SchemaStorage.AddModuleValuesSchemas(valuesModuleName, cb, vb)
if err != nil {
return nil, err
}
}

//
moduleValues, ok := initialValues[valuesModuleName].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("expect map[string]interface{} in module values")
}

bm := modules.NewBasicModule(module.Name, module.Path, module.Order, moduleValues, fl.valuesValidator)

result = append(result, bm)
}
}
Expand Down
1 change: 1 addition & 0 deletions pkg/module_manager/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import (

type ModuleLoader interface {
LoadModules() ([]*modules.BasicModule, error)
ReloadModule(string, string) (*modules.BasicModule, error)
}
32 changes: 32 additions & 0 deletions pkg/module_manager/models/moduleset/moduleset.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
package moduleset

import (
"errors"
"sort"
"sync"

"github.com/flant/addon-operator/pkg/module_manager/models/modules"
)

var (
ErrNotInited = errors.New("modules haven't been initilized yet")
)

type ModulesSet struct {
lck sync.RWMutex
modules map[string]*modules.BasicModule
orderedNames []string
inited bool
}

func (s *ModulesSet) SetInited() {
s.lck.Lock()
defer s.lck.Unlock()
s.inited = true
}

func (s *ModulesSet) IsInited() bool {
s.lck.RLock()
defer s.lck.RUnlock()
return s.inited
}

func (s *ModulesSet) Add(mods ...*modules.BasicModule) {
Expand Down Expand Up @@ -77,6 +95,20 @@ func (s *ModulesSet) Has(name string) bool {
return ok
}

func (s *ModulesSet) Update(module modules.BasicModule) {
found := s.Has(module.Name)

s.lck.Lock()
defer s.lck.Unlock()
if found {
delete(s.modules, module.Name)
} else {
s.orderedNames = nil
}

s.modules[module.Name] = &module
}

func (s *ModulesSet) sortModuleNames() []string {
// Get modules array.
mods := make([]*modules.BasicModule, 0, len(s.modules))
Expand Down
72 changes: 72 additions & 0 deletions pkg/module_manager/module_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/flant/addon-operator/pkg/module_manager/models/modules"
"github.com/flant/addon-operator/pkg/module_manager/models/modules/events"
"github.com/flant/addon-operator/pkg/module_manager/models/moduleset"
"github.com/flant/addon-operator/pkg/task"
"github.com/flant/addon-operator/pkg/utils"
"github.com/flant/addon-operator/pkg/values/validation"
. "github.com/flant/shell-operator/pkg/hook/binding_context"
Expand All @@ -36,6 +37,8 @@ import (
. "github.com/flant/shell-operator/pkg/kube_events_manager/types"
"github.com/flant/shell-operator/pkg/metric_storage"
"github.com/flant/shell-operator/pkg/schedule_manager"
sh_task "github.com/flant/shell-operator/pkg/task"
"github.com/flant/shell-operator/pkg/task/queue"
utils_checksum "github.com/flant/shell-operator/pkg/utils/checksum"
)

Expand Down Expand Up @@ -74,6 +77,7 @@ type ModuleManagerDependencies struct {
HelmResourcesManager helm_resources_manager.HelmResourcesManager
MetricStorage *metric_storage.MetricStorage
HookMetricStorage *metric_storage.MetricStorage
TaskQueue *queue.TaskQueue
}

type ModuleManagerConfig struct {
Expand Down Expand Up @@ -1028,6 +1032,73 @@ func mergeEnabled(enabledFlags ...*bool) bool {
return result
}

// ReregisterModule disable and deregister modules' hooks, and reload module config
func (mm *ModuleManager) ReregisterModule(moduleName, modulePath string) error {
if !mm.modules.IsInited() {
return moduleset.ErrNotInited
}

if mm.ModulesDir == "" {
log.Warnf("Empty modules directory is passed! No modules to load.")
return nil
}

if mm.moduleLoader == nil {
log.Errorf("no module loader set")
return fmt.Errorf("no module loader set")
}

mod, err := mm.moduleLoader.ReloadModule(moduleName, modulePath)
if err != nil {
return fmt.Errorf("failed to get module's definition: %w", err)
}

// load and registry global hooks
dep := &hooks.HookExecutionDependencyContainer{
HookMetricsStorage: mm.dependencies.HookMetricStorage,
KubeConfigManager: mm.dependencies.KubeConfigManager,
KubeObjectPatcher: mm.dependencies.KubeObjectPatcher,
MetricStorage: mm.dependencies.MetricStorage,
GlobalValuesGetter: mm.global,
}

mod.WithDependencies(dep)

// Deregister module
module := mm.GetModule(mod.GetName())
if module == nil {
return fmt.Errorf("Module %s wasn't found", moduleName)
}

if !mm.IsModuleEnabled(moduleName) {
mm.modules.Update(*mod)
return nil
}

mm.DisableModuleHooks(mod.GetName())
module.ResetState()
module.DeregisterHooks()

mm.modules.Update(*mod)

newTask := sh_task.NewTask(task.ModuleRun).
WithQueueName("main").
WithMetadata(task.HookMetadata{
EventDescription: "ModuleManager-Update-Module",
ModuleName: mod.GetName(),
})
newTask.SetProp("triggered-by", "ModuleManager")

mm.dependencies.TaskQueue.GetMain().AddLast(newTask.WithQueuedAt(time.Now()))

Check failure on line 1092 in pkg/module_manager/module_manager.go

View workflow job for this annotation

GitHub Actions / Run unit tests

mm.dependencies.TaskQueue.GetMain undefined (type *queue.TaskQueue has no field or method GetMain)

Check failure on line 1092 in pkg/module_manager/module_manager.go

View workflow job for this annotation

GitHub Actions / Build addon-operator binary

mm.dependencies.TaskQueue.GetMain undefined (type *queue.TaskQueue has no field or method GetMain)

Check failure on line 1092 in pkg/module_manager/module_manager.go

View workflow job for this annotation

GitHub Actions / Run Go linters

mm.dependencies.TaskQueue.GetMain undefined (type *queue.TaskQueue has no field or method GetMain)) (typecheck)

Check failure on line 1092 in pkg/module_manager/module_manager.go

View workflow job for this annotation

GitHub Actions / Run Go linters

mm.dependencies.TaskQueue.GetMain undefined (type *queue.TaskQueue has no field or method GetMain) (typecheck)

mm.moduleEventC <- events.ModuleEvent{
ModuleName: mod.GetName(),
EventType: events.ModuleEnabled,
}

return nil
}

// registerModules load all available modules from modules directory.
func (mm *ModuleManager) registerModules() error {
if mm.ModulesDir == "" {
Expand Down Expand Up @@ -1077,6 +1148,7 @@ func (mm *ModuleManager) registerModules() error {
log.Debugf("Found modules: %v", set.NamesInOrder())

mm.modules = set
mm.modules.SetInited()

return nil
}
Expand Down

0 comments on commit 8bf7f03

Please sign in to comment.