Skip to content

Commit

Permalink
[addon-operator] add module reregister (#432)
Browse files Browse the repository at this point in the history
Signed-off-by: Mikhail Scherba <mikhail.scherba@flant.com>
  • Loading branch information
miklezzzz authored Jan 12, 2024
1 parent 8102f46 commit e464020
Show file tree
Hide file tree
Showing 10 changed files with 442 additions and 59 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,
TaskQueues: op.engine.TaskQueues,
}

cfg := module_manager.ModuleManagerConfig{
Expand Down
2 changes: 1 addition & 1 deletion pkg/kube_config_manager/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type ConfigHandler interface {
StartInformer(ctx context.Context, eventC chan config.Event)

// LoadConfig loads initial modules config before starting the informer
LoadConfig(ctx context.Context) (*config.KubeConfig, error)
LoadConfig(ctx context.Context, modulesNames ...string) (*config.KubeConfig, error)

// SaveConfigValues saves patches for modules in backend (if supported), overriding the configuration
// Deprecated: saving values in the values source is not recommended and shouldn't be used anymore
Expand Down
4 changes: 2 additions & 2 deletions pkg/kube_config_manager/backend/configmap/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ func New(logger dlogger.Logger, kubeClient *client.Client, namespace, name strin
return backend
}

// LoadConfig gets config from ConfigMap before starting informer.
// LoadConfig gets config from ConfigMap before starting informer (selective loading configs for a list of modules isn't implemented).
// Set checksums for global section and modules.
func (b Backend) LoadConfig(ctx context.Context) (*config.KubeConfig, error) {
func (b Backend) LoadConfig(ctx context.Context, _ ...string) (*config.KubeConfig, error) {
obj, err := b.getConfigMap(ctx)
if err != nil {
return nil, err
Expand Down
27 changes: 27 additions & 0 deletions pkg/kube_config_manager/kube_config_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ func NewKubeConfigManager(ctx context.Context, bk backend.ConfigHandler, runtime
}
}

func (kcm *KubeConfigManager) IsModuleEnabled(moduleName string) bool {
moduleConfig, found := kcm.currentConfig.Modules[moduleName]
if !found {
return false
}

return moduleConfig.IsEnabled != nil && *moduleConfig.IsEnabled
}

func (kcm *KubeConfigManager) Init() error {
kcm.logEntry.Debug("Init: KubeConfigManager")

Expand Down Expand Up @@ -108,6 +117,24 @@ func (kcm *KubeConfigManager) KubeConfigEventCh() chan config.KubeConfigEvent {
return kcm.configEventCh
}

// UpdateModuleConfig updates a single module config
func (kcm *KubeConfigManager) UpdateModuleConfig(moduleName string) error {
newModuleConfig, err := kcm.backend.LoadConfig(kcm.ctx, moduleName)
if err != nil {
return err
}

if moduleConfig, found := newModuleConfig.Modules[moduleName]; found {
if kcm.knownChecksums != nil {
kcm.knownChecksums.Set(moduleName, moduleConfig.Checksum)
}

kcm.currentConfig.Modules[moduleName] = moduleConfig
}

return nil
}

// loadConfig gets config from ConfigMap before starting informer.
// Set checksums for global section and modules.
func (kcm *KubeConfigManager) loadConfig() error {
Expand Down
127 changes: 84 additions & 43 deletions pkg/module_manager/loader/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,78 @@ 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(_, modulePath string) (*modules.BasicModule, error) {
_, err := readDir(modulePath)
if err != nil {
return nil, err
}

commonStaticValues, err := utils.LoadValuesFileFromDir(modulePath)
if err != nil {
return nil, err
}

modDef, err := moduleFromDirName(filepath.Base(modulePath), modulePath)
if err != nil {
return nil, err
}

bm, err := fl.getBasicModule(modDef, commonStaticValues)
if err != nil {
return nil, err
}

return bm, nil
}

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

Expand All @@ -44,51 +116,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 All @@ -102,7 +133,8 @@ type moduleDefinition struct {
Order uint32
}

func (fl *FileSystemLoader) findModulesInDir(modulesDir string) ([]moduleDefinition, error) {
// checks if dir exists and returns entries
func readDir(modulesDir string) ([]os.DirEntry, error) {
dirEntries, err := os.ReadDir(modulesDir)
if err != nil && os.IsNotExist(err) {
return nil, fmt.Errorf("path '%s' does not exist", modulesDir)
Expand All @@ -111,6 +143,15 @@ func (fl *FileSystemLoader) findModulesInDir(modulesDir string) ([]moduleDefinit
return nil, fmt.Errorf("listing modules directory '%s': %s", modulesDir, err)
}

return dirEntries, nil
}

func (fl *FileSystemLoader) findModulesInDir(modulesDir string) ([]moduleDefinition, error) {
dirEntries, err := readDir(modulesDir)
if err != nil {
return nil, err
}

mods := make([]moduleDefinition, 0)
for _, dirEntry := range dirEntries {
name, absPath, err := resolveDirEntry(modulesDir, dirEntry)
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(moduleName string, modulePath string) (*modules.BasicModule, error)
}
3 changes: 3 additions & 0 deletions pkg/module_manager/models/modules/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ const (
type ModuleEvent struct {
ModuleName string
EventType ModuleEventType

// an option for registering a module without reload
Reregister bool
}
19 changes: 18 additions & 1 deletion pkg/module_manager/models/moduleset/moduleset.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
package moduleset

import (
"errors"
"sort"
"sync"

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

var ErrNotInited = errors.New("modules haven't been initialized 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
}

// adds a new module or overwrite an existing
func (s *ModulesSet) Add(mods ...*modules.BasicModule) {
if len(mods) == 0 {
return
Expand All @@ -27,7 +44,7 @@ func (s *ModulesSet) Add(mods ...*modules.BasicModule) {

for _, module := range mods {
// Invalidate ordered names cache.
if _, ok := s.modules[module.GetName()]; ok {
if _, ok := s.modules[module.GetName()]; !ok {
s.orderedNames = nil
}
s.modules[module.GetName()] = module
Expand Down
2 changes: 2 additions & 0 deletions pkg/module_manager/models/moduleset/moduleset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func TestBasicModuleSet(t *testing.T) {
Name: "BasicModule-four",
Order: 20,
})
ms.SetInited()

expectNames := []string{
"BasicModule-one",
Expand All @@ -49,4 +50,5 @@ func TestBasicModuleSet(t *testing.T) {
g.Expect(ms.NamesInOrder()).Should(Equal(expectNames))
g.Expect(ms.Has("BasicModule-four")).Should(BeTrue(), "should have BasicModule-four")
g.Expect(ms.Get("BasicModule-four").Order).Should(Equal(uint32(20)), "should have BasicModule-four with order:20")
g.Expect(ms.IsInited()).Should(BeTrue(), "should be inited")
}
Loading

0 comments on commit e464020

Please sign in to comment.