Skip to content

Commit

Permalink
fix: more responsive ConfigMap changes
Browse files Browse the repository at this point in the history
Huge refactoring to speedup reactions to ConfigMap changes. Fixes in enabled state
calculations.

KubeConfigManager is now responsible to signal if config is changed or invalid.

- fix: Update metric if ConfigMap is invalid (malformed module name or module values YAML)
- use runtime config to enable debug
- add locking

ModuleManager is now the only component that runs enabled scripts. It is responsible
for calculating ModulesReload/ReloadAll event. It lists Helm releases once at start
to detect initial enabled modules and modules to purge.

- fix: Fresh config values for enabled scripts (#184, #16)

AddonOperator uses task ConvergeModules to handle changes in ConfigMap or global values
and reload all modules or only changed.

- fix: ModulePurge tasks moved between GlobalSynchronization and first ConvergeModules (#233)
- fix: Clear queues from tasks for disabled module or errored hooks on ConfigMap changes (#43)
- ref: ConvergeModules is a new multi-phase task.

Other:
- mocks for HelmResourcesManager and KubeConfigManager
- Helm struct instead of global variables helm.NewClient and helm.HealthzHandler
- by dependabot: update gomega
  • Loading branch information
diafour committed Apr 25, 2022
1 parent 847d379 commit d2e392e
Show file tree
Hide file tree
Showing 99 changed files with 4,476 additions and 2,966 deletions.
17 changes: 8 additions & 9 deletions cmd/addon-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package main

import (
"fmt"
"math/rand"
"os"
"time"

"github.com/flant/kube-client/klogtologrus"
log "github.com/sirupsen/logrus"
"gopkg.in/alecthomas/kingpin.v2"

sh_app "github.com/flant/shell-operator/pkg/app"
"github.com/flant/shell-operator/pkg/config"
"github.com/flant/shell-operator/pkg/debug"
utils_signal "github.com/flant/shell-operator/pkg/utils/signal"

Expand Down Expand Up @@ -40,17 +40,16 @@ func main() {
startCmd := kpApp.Command("start", "Start events processing.").
Default().
Action(func(c *kingpin.ParseContext) error {
runtimeConfig := config.NewConfig()
// Init logging subsystem.
sh_app.SetupLogging(runtimeConfig)
log.Infof("%s %s, shell-operator %s", app.AppName, app.Version, sh_app.Version)
sh_app.AppStartMessage = fmt.Sprintf("%s %s, shell-operator %s", app.AppName, app.Version, sh_app.Version)

operator := addon_operator.DefaultOperator()
operator.WithRuntimeConfig(runtimeConfig)
err := addon_operator.InitAndStart(operator)
// Init rand generator.
rand.Seed(time.Now().UnixNano())

operator, err := addon_operator.Init()
if err != nil {
os.Exit(1)
}
operator.Start()

// Block action by waiting signals from OS.
utils_signal.WaitForProcessInterruption(func() {
Expand Down
8 changes: 5 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
module github.com/flant/addon-operator

go 1.15
go 1.16

require (
github.com/davecgh/go-spew v1.1.1
github.com/evanphx/json-patch v4.11.0+incompatible
github.com/flant/kube-client v0.0.6
github.com/flant/shell-operator v1.0.10-0.20220324171037-a48626e8b125
github.com/flant/shell-operator v1.0.10-0.20220411072300-19eb91114325
github.com/go-chi/chi v4.0.3+incompatible
github.com/go-openapi/spec v0.19.8
github.com/go-openapi/strfmt v0.19.5
github.com/go-openapi/swag v0.19.9
github.com/go-openapi/validate v0.19.12
github.com/hashicorp/go-multierror v1.1.1
github.com/kennygrant/sanitize v1.2.4
github.com/onsi/gomega v1.17.0
github.com/onsi/gomega v1.18.1
github.com/peterbourgon/mergemap v0.0.0-20130613134717-e21c03b7a721
github.com/prometheus/client_golang v1.11.0
github.com/segmentio/go-camelcase v0.0.0-20160726192923-7085f1e3c734
Expand Down Expand Up @@ -42,3 +42,5 @@ replace github.com/go-openapi/validate => github.com/flant/go-openapi-validate v
replace k8s.io/client-go => k8s.io/client-go v0.19.11

replace k8s.io/api => k8s.io/api v0.19.11

replace github.com/flant/shell-operator => ../shell-operator
14 changes: 10 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ github.com/flant/kube-client v0.0.6 h1:cHFMf7xGtJOgg+KBuPcA+7q+M7IJRSgf2pHVStv2a
github.com/flant/kube-client v0.0.6/go.mod h1:pVKIewJQ5oaBiE6AlTaWAUkd0548DEiyvkqkLaby3Zg=
github.com/flant/libjq-go v1.6.2-0.20200616114952-907039e8a02a h1:PlStPekqPtTSWDDKFlwgETsT1OiXD1gZtRHcNxAs1lc=
github.com/flant/libjq-go v1.6.2-0.20200616114952-907039e8a02a/go.mod h1:+SYqi5wsNjtQVlkPg0Ep5IOuN+ydg79Jo/gk4/PuS8c=
github.com/flant/shell-operator v1.0.10-0.20220324171037-a48626e8b125 h1:XaPqZE2PtFC0DQFHMX2w84SP+bAD3tYpRbFmOZVYMQk=
github.com/flant/shell-operator v1.0.10-0.20220324171037-a48626e8b125/go.mod h1:bHcTpRq0k0c/kaVQl6sODi/Nz8mqmtmMk9ff9dxrpN4=
github.com/flant/shell-operator v1.0.10-0.20220411072300-19eb91114325 h1:3E2JrvRsJvr6nLc8EIJuE29kTIqQdcAvX/neZKwN5oI=
github.com/flant/shell-operator v1.0.10-0.20220411072300-19eb91114325/go.mod h1:bHcTpRq0k0c/kaVQl6sODi/Nz8mqmtmMk9ff9dxrpN4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
Expand Down Expand Up @@ -391,6 +391,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand Down Expand Up @@ -454,6 +455,7 @@ github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
Expand Down Expand Up @@ -606,6 +608,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
Expand All @@ -614,8 +618,9 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
Expand Down Expand Up @@ -983,8 +988,9 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
130 changes: 130 additions & 0 deletions pkg/addon-operator/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package addon_operator

import (
"context"
"fmt"

sh_app "github.com/flant/shell-operator/pkg/app"
"github.com/flant/shell-operator/pkg/config"
"github.com/flant/shell-operator/pkg/debug"
shell_operator "github.com/flant/shell-operator/pkg/shell-operator"
log "github.com/sirupsen/logrus"

"github.com/flant/addon-operator/pkg/app"
"github.com/flant/addon-operator/pkg/helm"
"github.com/flant/addon-operator/pkg/kube_config_manager"
"github.com/flant/addon-operator/pkg/module_manager"
)

func Init() (*AddonOperator, error) {
runtimeConfig := config.NewConfig()
// Init logging subsystem.
sh_app.SetupLogging(runtimeConfig)
log.Infof(sh_app.AppStartMessage)

modulesDir, err := shell_operator.RequireExistingDirectory(app.ModulesDir)
if err != nil {
log.Errorf("Fatal: modules directory: %s", err)
return nil, err
}
log.Infof("Modules directory: %s", modulesDir)

globalHooksDir, err := shell_operator.RequireExistingDirectory(app.GlobalHooksDir)
if err != nil {
log.Errorf("Fatal: global hooks directory: %s", err)
return nil, err
}
log.Infof("Global hooks directory: %s", globalHooksDir)

tempDir, err := shell_operator.EnsureTempDirectory(sh_app.TempDir)
if err != nil {
log.Errorf("Fatal: temp directory: %s", err)
return nil, err
}

log.Infof("Addon-operator namespace: %s", app.Namespace)

op := NewAddonOperator()
op.WithContext(context.Background())

// Debug server.
debugServer, err := shell_operator.InitDefaultDebugServer()
if err != nil {
log.Errorf("Fatal: start Debug server: %s", err)
return nil, err
}

err = shell_operator.AssembleCommonOperator(op.ShellOperator)
if err != nil {
log.Errorf("Fatal: %s", err)
return nil, err
}

err = AssembleAddonOperator(op, modulesDir, globalHooksDir, tempDir, debugServer, runtimeConfig)
if err != nil {
log.Errorf("Fatal: %s", err)
return nil, err
}

return op, nil
}

func AssembleAddonOperator(op *AddonOperator, modulesDir string, globalHooksDir string, tempDir string, debugServer *debug.Server, runtimeConfig *config.Config) (err error) {
RegisterDefaultRoutes(op)
RegisterAddonOperatorMetrics(op.MetricStorage)
StartLiveTicksUpdater(op.MetricStorage)
StartTasksQueueLengthUpdater(op.MetricStorage, op.TaskQueues)

// Register routes in debug server.
shell_operator.RegisterDebugQueueRoutes(debugServer, op.ShellOperator)
shell_operator.RegisterDebugConfigRoutes(debugServer, runtimeConfig)
RegisterDebugGlobalRoutes(debugServer, op)
RegisterDebugModuleRoutes(debugServer, op)

// Helm client factory.
op.Helm = helm.New()
op.Helm.WithKubeClient(op.KubeClient)
err = op.Helm.Init()
if err != nil {
return fmt.Errorf("initialize Helm: %s", err)
}

// Helm resources monitor.
// It uses a separate client-go instance. (Metrics are registered when 'main' client is initialized).
op.HelmResourcesManager, err = InitDefaultHelmResourcesManager(op.ctx, op.MetricStorage)
if err != nil {
return fmt.Errorf("initialize Helm resources manager: %s", err)
}

SetupModuleManager(op, modulesDir, globalHooksDir, tempDir, runtimeConfig)

err = op.InitModuleManager()
if err != nil {
return err
}

return nil
}

func SetupModuleManager(op *AddonOperator, modulesDir string, globalHooksDir string, tempDir string, runtimeConfig *config.Config) {
// Create manager to check values in ConfigMap.
op.KubeConfigManager = kube_config_manager.NewKubeConfigManager()
op.KubeConfigManager.WithKubeClient(op.KubeClient)
op.KubeConfigManager.WithContext(op.ctx)
op.KubeConfigManager.WithNamespace(app.Namespace)
op.KubeConfigManager.WithConfigMapName(app.ConfigMapName)
op.KubeConfigManager.WithRuntimeConfig(runtimeConfig)

// Create manager that runs modules and hooks.
op.ModuleManager = module_manager.NewModuleManager()
op.ModuleManager.WithContext(op.ctx)
op.ModuleManager.WithDirectories(modulesDir, globalHooksDir, tempDir)
op.ModuleManager.WithKubeConfigManager(op.KubeConfigManager)
op.ModuleManager.WithHelm(op.Helm)
op.ModuleManager.WithScheduleManager(op.ScheduleManager)
op.ModuleManager.WithKubeEventManager(op.KubeEventsManager)
op.ModuleManager.WithKubeObjectPatcher(op.ObjectPatcher)
op.ModuleManager.WithMetricStorage(op.MetricStorage)
op.ModuleManager.WithHookMetricStorage(op.HookMetricStorage)
op.ModuleManager.WithHelmResourcesManager(op.HelmResourcesManager)
}
91 changes: 91 additions & 0 deletions pkg/addon-operator/converge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package addon_operator

import (
"time"

sh_task "github.com/flant/shell-operator/pkg/task"

. "github.com/flant/addon-operator/pkg/hook/types"
"github.com/flant/addon-operator/pkg/task"
)

type ConvergeState struct {
Phase ConvergePhase
FirstStarted bool
FirstDone bool
StartedAt int64
Activation string
}

type ConvergePhase string

const (
StandBy ConvergePhase = "StandBy"
RunBeforeAll ConvergePhase = "RunBeforeAll"
WaitBeforeAll ConvergePhase = "WaitBeforeAll"
WaitDeleteAndRunModules ConvergePhase = "WaitDeleteAndRunModules"
WaitAfterAll ConvergePhase = "WaitAfterAll"
)

func NewConvergeState() *ConvergeState {
return &ConvergeState{
Phase: StandBy,
}
}

const ConvergeEventProp = "converge.event"

type ConvergeEvent string

const (
// OperatorStartup is a first converge during startup.
OperatorStartup ConvergeEvent = "OperatorStartup"
// GlobalValuesChanged is a converge initiated by changing values in the global hook.
GlobalValuesChanged ConvergeEvent = "GlobalValuesChanged"
// KubeConfigChanged is a converge started after changing ConfigMap.
KubeConfigChanged ConvergeEvent = "KubeConfigChanged"
// ReloadAllModules is a converge queued to the
ReloadAllModules ConvergeEvent = "ReloadAllModules"
)

func IsConvergeTask(t sh_task.Task) bool {
taskType := t.GetType()
switch taskType {
case task.ModuleDelete, task.ModuleRun, task.ConvergeModules:
return true
}
hm := task.HookMetadataAccessor(t)
switch taskType {
case task.GlobalHookRun:
switch hm.BindingType {
case BeforeAll, AfterAll:
return true
}
case task.ModuleHookRun:
if hm.IsSynchronization() {
return true
}
}
return false
}

func IsFirstConvergeTask(t sh_task.Task) bool {
taskType := t.GetType()
switch taskType {
case task.ModulePurge, task.DiscoverHelmReleases, task.GlobalHookEnableKubernetesBindings, task.GlobalHookEnableScheduleBindings:
return true
}
return false
}

func NewConvergeModulesTask(description string, convergeEvent ConvergeEvent, logLabels map[string]string) sh_task.Task {
convergeTask := sh_task.NewTask(task.ConvergeModules).
WithLogLabels(logLabels).
WithQueueName("main").
WithMetadata(task.HookMetadata{
EventDescription: description,
}).
WithQueuedAt(time.Now())
convergeTask.SetProp(ConvergeEventProp, convergeEvent)
return convergeTask
}
Loading

0 comments on commit d2e392e

Please sign in to comment.