-
Notifications
You must be signed in to change notification settings - Fork 49
DVO-111: Dynamic validation engine #263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
openshift-merge-robot
merged 41 commits into
app-sre:master
from
ncaak:DVO-111/dynamic-validation-engine
Sep 13, 2023
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
1ffe549
Add filter for other ConfigMaps within the same namespace
ncaak 12ad75b
Add validationEngine and watcher to reconcilier
ncaak bfbed74
Add initializer and accessible function from struct
ncaak db7ff74
Fix Manager setup to account for validationEngine and watcher
ncaak 36f192b
Fix missing channel
ncaak 2d169d1
Decouple Prometheus registry initialization
ncaak 5496b73
Fix missing interface change
ncaak 878979f
Add new utils functions for Prometheus registry decoupling
ncaak 833c15a
Fix global variable missleading
ncaak e38100b
Refactor validation engine package WIP
ncaak 7c572b7
Refactor re-use existing methods on VE
ncaak c94677c
Refactor minor changes on initializacion
ncaak 9642fa1
WIP Move configmap watcher to its own package
ncaak 706daed
Refactor main script to improve readability
ncaak ed1d8b8
Fix redundant system trigger of the informer
ncaak aef2a12
Rollback VE and CMW dependencies and interface
ncaak 08cc888
Move CMW control to VE package
ncaak cab232a
Update comments
ncaak 4efd6f4
Fix linting recommendations
ncaak 3288463
WIP Refactor metrics used on Prom registry to be used in VE struct
ncaak 0d9235d
Update documentation
ncaak 9fa2b71
Fix loglines prefixes
ncaak 2a35cf6
Fix linter issues
ncaak 3bea7df
Fix missing prefix on metrics
ncaak b570cdb
Fix unit tests breaking due to metrics preload
ncaak 2a3abee
Fix nit recommendations
ncaak 99e05d2
Add dynamic namespace setting on watcher
ncaak dc54e41
Fix unit tests
ncaak 134b73c
Use Pod instead of deployment for namespace
ncaak f51630d
Move back Watcher to reconcilier
ncaak c32a514
Add accesses for reconcilier
ncaak dc542f1
Remove Watcher from VE and fix main script
ncaak df2b040
Refactor loglines and pod namespace gather function
ncaak 5fbf0c6
Add new logic for removing unexistent checks from configuration
ncaak 9e2dfeb
Minor refactoring
ncaak d5af598
Add missing documentation and fix tests
ncaak 9eeda44
Unexport validation engine structure as now it's not handled outside …
ncaak 994c690
Add missing operator.yaml fix to get new namespace ENV variable
ncaak 8625560
Add delete scenario in the watcher
ncaak 043a69f
Minor refactoring
ncaak 4f6c8fe
Bundle regenerated with missing env variable
ncaak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| package configmap | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "reflect" | ||
| "time" | ||
|
|
||
| "golang.stackrox.io/kube-linter/pkg/config" | ||
| "gopkg.in/yaml.v3" | ||
|
|
||
| "github.com/app-sre/deployment-validation-operator/pkg/validations" | ||
| "github.com/go-logr/logr" | ||
| apicorev1 "k8s.io/api/core/v1" | ||
| v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/client-go/informers" | ||
| "k8s.io/client-go/kubernetes" | ||
| "k8s.io/client-go/rest" | ||
| "k8s.io/client-go/tools/cache" | ||
| "sigs.k8s.io/controller-runtime/pkg/log" | ||
| ) | ||
|
|
||
| // this structure mirrors Kube-Linter configuration structure | ||
| // it is used as a bridge to unmarshall ConfigMap data | ||
| // doc: https://pkg.go.dev/golang.stackrox.io/kube-linter/pkg/config#Config | ||
| type KubeLinterChecks struct { | ||
| Checks struct { | ||
| AddAllBuiltIn bool `yaml:"addAllBuiltIn,omitempty"` | ||
| DoNotAutoAddDefaults bool `yaml:"doNotAutoAddDefaults,omitempty"` | ||
| Exclude []string `yaml:"exclude,omitempty"` | ||
| Include []string `yaml:"include,omitempty"` | ||
| IgnorePaths []string `yaml:"ignorePaths,omitempty"` | ||
| } `yaml:"checks"` | ||
| } | ||
|
|
||
| type Watcher struct { | ||
| clientset kubernetes.Interface | ||
| checks KubeLinterChecks | ||
| ch chan config.Config | ||
| logger logr.Logger | ||
| namespace string | ||
| } | ||
|
|
||
| var configMapName = "deployment-validation-operator-config" | ||
| var configMapDataAccess = "deployment-validation-operator-config.yaml" | ||
|
|
||
| // NewWatcher creates a new Watcher instance for observing changes to a ConfigMap. | ||
| // | ||
| // Parameters: | ||
| // - cfg: A pointer to a rest.Config representing the Kubernetes client configuration. | ||
| // | ||
| // Returns: | ||
| // - A pointer to a Watcher instance for monitoring changes to DVO ConfigMap resource. | ||
| // - An error if there's an issue while initializing the Kubernetes clientset. | ||
| func NewWatcher(cfg *rest.Config) (*Watcher, error) { | ||
| clientset, err := kubernetes.NewForConfig(cfg) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("initializing clientset: %w", err) | ||
| } | ||
|
|
||
| // the Informer will use this to monitor the namespace for the ConfigMap. | ||
| namespace, err := getPodNamespace() | ||
| if err != nil { | ||
| return nil, fmt.Errorf("getting namespace: %w", err) | ||
| } | ||
|
|
||
| return &Watcher{ | ||
| clientset: clientset, | ||
| logger: log.Log.WithName("ConfigMapWatcher"), | ||
| ch: make(chan config.Config), | ||
| namespace: namespace, | ||
| }, nil | ||
| } | ||
|
|
||
| // GetStaticKubelinterConfig returns the ConfigMap's checks configuration | ||
| func (cmw *Watcher) GetStaticKubelinterConfig(ctx context.Context) (config.Config, error) { | ||
| cm, err := cmw.clientset.CoreV1(). | ||
| ConfigMaps(cmw.namespace).Get(ctx, configMapName, v1.GetOptions{}) | ||
| if err != nil { | ||
| return config.Config{}, fmt.Errorf("getting initial configuration: %w", err) | ||
| } | ||
|
|
||
| return cmw.getKubeLinterConfig(cm.Data[configMapDataAccess]) | ||
| } | ||
|
|
||
| // Start will update the channel structure with new configuration data from ConfigMap update event | ||
| func (cmw Watcher) Start(ctx context.Context) error { | ||
| factory := informers.NewSharedInformerFactoryWithOptions( | ||
| cmw.clientset, time.Second*30, informers.WithNamespace(cmw.namespace), | ||
| ) | ||
| informer := factory.Core().V1().ConfigMaps().Informer() | ||
|
|
||
| informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ // nolint:errcheck | ||
| AddFunc: func(obj interface{}) { | ||
| newCm := obj.(*apicorev1.ConfigMap) | ||
|
|
||
| if configMapName != newCm.GetName() { | ||
| return | ||
| } | ||
|
|
||
| cmw.logger.Info( | ||
| "a ConfigMap has been created under watched namespace", | ||
| "name", newCm.GetName(), | ||
| "namespace", newCm.GetNamespace(), | ||
| ) | ||
|
|
||
| cfg, err := cmw.getKubeLinterConfig(newCm.Data[configMapDataAccess]) | ||
| if err != nil { | ||
| cmw.logger.Error(err, "ConfigMap data format") | ||
ncaak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return | ||
| } | ||
|
|
||
| cmw.ch <- cfg | ||
| }, | ||
| UpdateFunc: func(oldObj, newObj interface{}) { | ||
| newCm := newObj.(*apicorev1.ConfigMap) | ||
|
|
||
| // This is sometimes triggered even if no change was due to the ConfigMap | ||
| if configMapName != newCm.GetName() || reflect.DeepEqual(oldObj, newObj) { | ||
| return | ||
| } | ||
|
|
||
| cmw.logger.Info( | ||
| "a ConfigMap has been updated under watched namespace", | ||
| "name", newCm.GetName(), | ||
| "namespace", newCm.GetNamespace(), | ||
| ) | ||
ncaak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| cfg, err := cmw.getKubeLinterConfig(newCm.Data[configMapDataAccess]) | ||
| if err != nil { | ||
| cmw.logger.Error(err, "ConfigMap data format") | ||
| return | ||
| } | ||
|
|
||
| cmw.ch <- cfg | ||
| }, | ||
| DeleteFunc: func(oldObj interface{}) { | ||
| cm := oldObj.(*apicorev1.ConfigMap) | ||
|
|
||
| cmw.logger.Info( | ||
| "a ConfigMap has been deleted under watched namespace", | ||
| "name", cm.GetName(), | ||
| "namespace", cm.GetNamespace(), | ||
| ) | ||
|
|
||
| cmw.ch <- config.Config{ | ||
| Checks: validations.GetDefaultChecks(), | ||
| } | ||
| }, | ||
| }) | ||
|
|
||
| factory.Start(ctx.Done()) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // ConfigChanged receives push notifications when the configuration is updated | ||
| func (cmw *Watcher) ConfigChanged() <-chan config.Config { | ||
| return cmw.ch | ||
| } | ||
|
|
||
| // getKubeLinterConfig returns a valid Kube-linter Config structure | ||
| // based on the checks received by the string | ||
| func (cmw *Watcher) getKubeLinterConfig(data string) (config.Config, error) { | ||
| var cfg config.Config | ||
|
|
||
| err := yaml.Unmarshal([]byte(data), &cmw.checks) | ||
| if err != nil { | ||
| return cfg, fmt.Errorf("unmarshalling configmap data: %w", err) | ||
| } | ||
|
|
||
| cfg.Checks = config.ChecksConfig(cmw.checks.Checks) | ||
|
|
||
| return cfg, nil | ||
| } | ||
|
|
||
| func getPodNamespace() (string, error) { | ||
| namespace, exists := os.LookupEnv("POD_NAMESPACE") | ||
ncaak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if !exists { | ||
| return "", fmt.Errorf("could not find DVO pod") | ||
| } | ||
ncaak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return namespace, nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.