From 721fc8400eff42dfbc109d9a57b147e30cafac90 Mon Sep 17 00:00:00 2001 From: Yuriy Losev Date: Wed, 18 Sep 2024 13:20:44 +0400 Subject: [PATCH] refactor webhook --- pkg/app/webhook.go | 1 - pkg/hook/binding_context/binding_context.go | 4 +- .../conversion_bindings_controller.go | 57 ++++--- pkg/hook/controller/hook_controller.go | 148 +++++++++--------- pkg/hook/hook.go | 4 +- pkg/hook/hook_manager.go | 71 +++------ pkg/hook/hook_manager_test.go | 4 +- pkg/metric_storage/vault/collector.go | 2 - pkg/shell-operator/bootstrap.go | 2 +- pkg/shell-operator/operator.go | 46 +++--- pkg/utils/file/file.go | 1 - pkg/utils/file/file_test.go | 6 +- pkg/webhook/conversion/event.go | 37 ++--- pkg/webhook/conversion/handler.go | 106 ++++--------- pkg/webhook/conversion/manager.go | 6 +- pkg/webhook/conversion/response.go | 6 +- test/hook/context/context_combiner.go | 2 +- test/hook/context/generator.go | 5 +- 18 files changed, 212 insertions(+), 296 deletions(-) diff --git a/pkg/app/webhook.go b/pkg/app/webhook.go index 807673b0..f6b36ecc 100644 --- a/pkg/app/webhook.go +++ b/pkg/app/webhook.go @@ -110,5 +110,4 @@ func DefineConversionWebhookFlags(cmd *kingpin.CmdClause) { Default(ConversionWebhookSettings.ListenAddr). Envar("CONVERSION_WEBHOOK_LISTEN_ADDRESS"). StringVar(&ConversionWebhookSettings.ListenAddr) - } diff --git a/pkg/hook/binding_context/binding_context.go b/pkg/hook/binding_context/binding_context.go index 1851e82e..50be9be4 100644 --- a/pkg/hook/binding_context/binding_context.go +++ b/pkg/hook/binding_context/binding_context.go @@ -2,9 +2,9 @@ package binding_context import ( "encoding/json" - log "github.com/sirupsen/logrus" v1 "k8s.io/api/admission/v1" + v12 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" . "github.com/flant/shell-operator/pkg/hook/types" . "github.com/flant/shell-operator/pkg/kube_events_manager/types" @@ -29,7 +29,7 @@ type BindingContext struct { Objects []ObjectAndFilterResult Snapshots map[string][]ObjectAndFilterResult AdmissionReview *v1.AdmissionReview - ConversionReview map[string]interface{} + ConversionReview *v12.ConversionReview FromVersion string ToVersion string } diff --git a/pkg/hook/controller/conversion_bindings_controller.go b/pkg/hook/controller/conversion_bindings_controller.go index 8a1d91de..148f80c9 100644 --- a/pkg/hook/controller/conversion_bindings_controller.go +++ b/pkg/hook/controller/conversion_bindings_controller.go @@ -2,6 +2,7 @@ package controller import ( log "github.com/sirupsen/logrus" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" . "github.com/flant/shell-operator/pkg/hook/binding_context" . "github.com/flant/shell-operator/pkg/hook/types" @@ -19,18 +20,18 @@ type ConversionBindingToWebhookLink struct { Group string } -// ScheduleBindingsController handles schedule bindings for one hook. -type ConversionBindingsController interface { - WithBindings([]ConversionConfig) - WithWebhookManager(manager *conversion.WebhookManager) - EnableConversionBindings() - DisableConversionBindings() - CanHandleEvent(event conversion.Event, rule conversion.Rule) bool - HandleEvent(event conversion.Event, rule conversion.Rule) BindingExecutionInfo -} - -// Controller holds validating bindings from one hook. -type conversionBindingsController struct { +//// ScheduleBindingsController handles schedule bindings for one hook. +// type ConversionBindingsController interface { +// WithBindings([]ConversionConfig) +// WithWebhookManager(manager *conversion.WebhookManager) +// EnableConversionBindings() +// DisableConversionBindings() +// CanHandleEvent(event conversion.Event, rule conversion.Rule) bool +// HandleEvent(event conversion.Event, rule conversion.Rule) BindingExecutionInfo +//} + +// ConversionBindingsController holds validating bindings from one hook. +type ConversionBindingsController struct { // crdName -> conversionRule id -> link Links map[string]map[conversion.Rule]*ConversionBindingToWebhookLink @@ -39,24 +40,22 @@ type conversionBindingsController struct { webhookManager *conversion.WebhookManager } -var _ ConversionBindingsController = &conversionBindingsController{} - // NewConversionBindingsController returns an implementation of ConversionBindingsController -var NewConversionBindingsController = func() *conversionBindingsController { - return &conversionBindingsController{ +var NewConversionBindingsController = func() *ConversionBindingsController { + return &ConversionBindingsController{ Links: make(map[string]map[conversion.Rule]*ConversionBindingToWebhookLink), } } -func (c *conversionBindingsController) WithBindings(bindings []ConversionConfig) { +func (c *ConversionBindingsController) WithBindings(bindings []ConversionConfig) { c.Bindings = bindings } -func (c *conversionBindingsController) WithWebhookManager(mgr *conversion.WebhookManager) { +func (c *ConversionBindingsController) WithWebhookManager(mgr *conversion.WebhookManager) { c.webhookManager = mgr } -func (c *conversionBindingsController) EnableConversionBindings() { +func (c *ConversionBindingsController) EnableConversionBindings() { // Setup links and inform webhookManager about webhooks. for _, config := range c.Bindings { if _, ok := c.Links[config.Webhook.CrdName]; !ok { @@ -76,31 +75,31 @@ func (c *conversionBindingsController) EnableConversionBindings() { } } -func (c *conversionBindingsController) DisableConversionBindings() { +func (c *ConversionBindingsController) DisableConversionBindings() { // TODO dynamic enable/disable conversion webhooks. } -func (c *conversionBindingsController) CanHandleEvent(event conversion.Event, rule conversion.Rule) bool { - _, has := c.Links[event.CrdName] +func (c *ConversionBindingsController) CanHandleEvent(crdName string, event *v1.ConversionReview, rule conversion.Rule) bool { + _, has := c.Links[event.Request.DesiredAPIVersion] if !has { return false } - _, has = c.Links[event.CrdName][rule] + _, has = c.Links[crdName][rule] return has } -func (c *conversionBindingsController) HandleEvent(event conversion.Event, rule conversion.Rule) BindingExecutionInfo { - _, hasKey := c.Links[event.CrdName] +func (c *ConversionBindingsController) HandleEvent(crdName string, event *v1.ConversionReview, rule conversion.Rule) BindingExecutionInfo { + _, hasKey := c.Links[crdName] if !hasKey { - log.Errorf("Possible bug!!! No binding for conversion event for crd/%s", event.CrdName) + log.Errorf("Possible bug!!! No binding for conversion event for crd/%s", crdName) return BindingExecutionInfo{ BindingContext: []BindingContext{}, AllowFailure: false, } } - link, has := c.Links[event.CrdName][rule] + link, has := c.Links[crdName][rule] if !has { - log.Errorf("Possible bug!!! Event has an unknown conversion rule %s for crd/%s: no binding was registered", rule.String(), event.CrdName) + log.Errorf("Possible bug!!! Event has an unknown conversion rule %s for crd/%s: no binding was registered", rule.String(), crdName) return BindingExecutionInfo{ BindingContext: []BindingContext{}, AllowFailure: false, @@ -109,7 +108,7 @@ func (c *conversionBindingsController) HandleEvent(event conversion.Event, rule bc := BindingContext{ Binding: link.BindingName, - ConversionReview: event.GetReview(), + ConversionReview: event, FromVersion: link.FromVersion, ToVersion: link.ToVersion, } diff --git a/pkg/hook/controller/hook_controller.go b/pkg/hook/controller/hook_controller.go index d212599e..708f43ab 100644 --- a/pkg/hook/controller/hook_controller.go +++ b/pkg/hook/controller/hook_controller.go @@ -1,6 +1,8 @@ package controller import ( + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + . "github.com/flant/shell-operator/pkg/hook/binding_context" . "github.com/flant/shell-operator/pkg/hook/types" "github.com/flant/shell-operator/pkg/kube_events_manager" @@ -33,54 +35,52 @@ type BindingExecutionInfo struct { // методом KubernetesSnapshots можно достать все кубовые объекты, чтобы добавить // их в какой-то свой binding context -type HookController interface { - InitKubernetesBindings([]OnKubernetesEventConfig, kube_events_manager.KubeEventsManager) - InitScheduleBindings([]ScheduleConfig, schedule_manager.ScheduleManager) - InitAdmissionBindings([]ValidatingConfig, []MutatingConfig, *admission.WebhookManager) - InitConversionBindings([]ConversionConfig, *conversion.WebhookManager) - - CanHandleKubeEvent(kubeEvent KubeEvent) bool - CanHandleScheduleEvent(crontab string) bool - CanHandleAdmissionEvent(event AdmissionEvent) bool - CanHandleConversionEvent(event conversion.Event, rule conversion.Rule) bool - - // These method should call an underlying *Binding*Controller to get binding context - // and then add Snapshots to binding context - HandleEnableKubernetesBindings(createTasksFn func(BindingExecutionInfo)) error - HandleKubeEvent(event KubeEvent, createTasksFn func(BindingExecutionInfo)) - HandleScheduleEvent(crontab string, createTasksFn func(BindingExecutionInfo)) - HandleAdmissionEvent(event AdmissionEvent, createTasksFn func(BindingExecutionInfo)) - HandleConversionEvent(event conversion.Event, rule conversion.Rule, createTasksFn func(BindingExecutionInfo)) - - UnlockKubernetesEvents() - UnlockKubernetesEventsFor(monitorID string) - StopMonitors() - UpdateMonitor(monitorId string, kind, apiVersion string) error - - EnableScheduleBindings() - DisableScheduleBindings() - - EnableAdmissionBindings() - - EnableConversionBindings() - - KubernetesSnapshots() map[string][]ObjectAndFilterResult - UpdateSnapshots([]BindingContext) []BindingContext - SnapshotsInfo() []string - SnapshotsDump() map[string]interface{} -} - -var _ HookController = &hookController{} +// type HookController interface { +// InitKubernetesBindings([]OnKubernetesEventConfig, kube_events_manager.KubeEventsManager) +// InitScheduleBindings([]ScheduleConfig, schedule_manager.ScheduleManager) +// InitAdmissionBindings([]ValidatingConfig, []MutatingConfig, *admission.WebhookManager) +// InitConversionBindings([]ConversionConfig, *conversion.WebhookManager) +// +// CanHandleKubeEvent(kubeEvent KubeEvent) bool +// CanHandleScheduleEvent(crontab string) bool +// CanHandleAdmissionEvent(event AdmissionEvent) bool +// CanHandleConversionEvent(event conversion.Event, rule conversion.Rule) bool +// +// // These method should call an underlying *Binding*Controller to get binding context +// // and then add Snapshots to binding context +// HandleEnableKubernetesBindings(createTasksFn func(BindingExecutionInfo)) error +// HandleKubeEvent(event KubeEvent, createTasksFn func(BindingExecutionInfo)) +// HandleScheduleEvent(crontab string, createTasksFn func(BindingExecutionInfo)) +// HandleAdmissionEvent(event AdmissionEvent, createTasksFn func(BindingExecutionInfo)) +// HandleConversionEvent(event conversion.Event, rule conversion.Rule, createTasksFn func(BindingExecutionInfo)) +// +// UnlockKubernetesEvents() +// UnlockKubernetesEventsFor(monitorID string) +// StopMonitors() +// UpdateMonitor(monitorId string, kind, apiVersion string) error +// +// EnableScheduleBindings() +// DisableScheduleBindings() +// +// EnableAdmissionBindings() +// +// EnableConversionBindings() +// +// KubernetesSnapshots() map[string][]ObjectAndFilterResult +// UpdateSnapshots([]BindingContext) []BindingContext +// SnapshotsInfo() []string +// SnapshotsDump() map[string]interface{} +//} -func NewHookController() HookController { - return &hookController{} +func NewHookController() *HookController { + return &HookController{} } -type hookController struct { +type HookController struct { KubernetesController KubernetesBindingsController ScheduleController ScheduleBindingsController AdmissionController AdmissionBindingsController - ConversionController ConversionBindingsController + ConversionController *ConversionBindingsController kubernetesBindings []OnKubernetesEventConfig scheduleBindings []ScheduleConfig validatingBindings []ValidatingConfig @@ -88,7 +88,7 @@ type hookController struct { conversionBindings []ConversionConfig } -func (hc *hookController) InitKubernetesBindings(bindings []OnKubernetesEventConfig, kubeEventMgr kube_events_manager.KubeEventsManager) { +func (hc *HookController) InitKubernetesBindings(bindings []OnKubernetesEventConfig, kubeEventMgr kube_events_manager.KubeEventsManager) { if len(bindings) == 0 { return } @@ -100,7 +100,7 @@ func (hc *hookController) InitKubernetesBindings(bindings []OnKubernetesEventCon hc.kubernetesBindings = bindings } -func (hc *hookController) InitScheduleBindings(bindings []ScheduleConfig, scheduleMgr schedule_manager.ScheduleManager) { +func (hc *HookController) InitScheduleBindings(bindings []ScheduleConfig, scheduleMgr schedule_manager.ScheduleManager) { if len(bindings) == 0 { return } @@ -112,7 +112,7 @@ func (hc *hookController) InitScheduleBindings(bindings []ScheduleConfig, schedu hc.scheduleBindings = bindings } -func (hc *hookController) InitAdmissionBindings(vbindings []ValidatingConfig, mbindings []MutatingConfig, webhookMgr *admission.WebhookManager) { +func (hc *HookController) InitAdmissionBindings(vbindings []ValidatingConfig, mbindings []MutatingConfig, webhookMgr *admission.WebhookManager) { bindingCtrl := NewValidatingBindingsController() bindingCtrl.WithWebhookManager(webhookMgr) hc.AdmissionController = bindingCtrl @@ -121,7 +121,7 @@ func (hc *hookController) InitAdmissionBindings(vbindings []ValidatingConfig, mb hc.initMutatingBindings(mbindings) } -func (hc *hookController) initValidatingBindings(bindings []ValidatingConfig) { +func (hc *HookController) initValidatingBindings(bindings []ValidatingConfig) { if len(bindings) == 0 { return } @@ -130,7 +130,7 @@ func (hc *hookController) initValidatingBindings(bindings []ValidatingConfig) { hc.validatingBindings = bindings } -func (hc *hookController) initMutatingBindings(bindings []MutatingConfig) { +func (hc *HookController) initMutatingBindings(bindings []MutatingConfig) { if len(bindings) == 0 { return } @@ -139,7 +139,7 @@ func (hc *hookController) initMutatingBindings(bindings []MutatingConfig) { hc.mutatingBindings = bindings } -func (hc *hookController) InitConversionBindings(bindings []ConversionConfig, webhookMgr *conversion.WebhookManager) { +func (hc *HookController) InitConversionBindings(bindings []ConversionConfig, webhookMgr *conversion.WebhookManager) { if len(bindings) == 0 { return } @@ -151,35 +151,35 @@ func (hc *hookController) InitConversionBindings(bindings []ConversionConfig, we hc.conversionBindings = bindings } -func (hc *hookController) CanHandleKubeEvent(kubeEvent KubeEvent) bool { +func (hc *HookController) CanHandleKubeEvent(kubeEvent KubeEvent) bool { if hc.KubernetesController != nil { return hc.KubernetesController.CanHandleEvent(kubeEvent) } return false } -func (hc *hookController) CanHandleScheduleEvent(crontab string) bool { +func (hc *HookController) CanHandleScheduleEvent(crontab string) bool { if hc.ScheduleController != nil { return hc.ScheduleController.CanHandleEvent(crontab) } return false } -func (hc *hookController) CanHandleAdmissionEvent(event AdmissionEvent) bool { +func (hc *HookController) CanHandleAdmissionEvent(event AdmissionEvent) bool { if hc.AdmissionController != nil { return hc.AdmissionController.CanHandleEvent(event) } return false } -func (hc *hookController) CanHandleConversionEvent(event conversion.Event, rule conversion.Rule) bool { +func (hc *HookController) CanHandleConversionEvent(crdName string, event *v1.ConversionReview, rule conversion.Rule) bool { if hc.ConversionController != nil { - return hc.ConversionController.CanHandleEvent(event, rule) + return hc.ConversionController.CanHandleEvent(crdName, event, rule) } return false } -func (hc *hookController) HandleEnableKubernetesBindings(createTasksFn func(BindingExecutionInfo)) error { +func (hc *HookController) HandleEnableKubernetesBindings(createTasksFn func(BindingExecutionInfo)) error { if hc.KubernetesController != nil { execInfos, err := hc.KubernetesController.EnableKubernetesBindings() if err != nil { @@ -195,7 +195,7 @@ func (hc *hookController) HandleEnableKubernetesBindings(createTasksFn func(Bind return nil } -func (hc *hookController) HandleKubeEvent(event KubeEvent, createTasksFn func(BindingExecutionInfo)) { +func (hc *HookController) HandleKubeEvent(event KubeEvent, createTasksFn func(BindingExecutionInfo)) { if hc.KubernetesController != nil { execInfo := hc.KubernetesController.HandleEvent(event) if createTasksFn != nil { @@ -204,7 +204,7 @@ func (hc *hookController) HandleKubeEvent(event KubeEvent, createTasksFn func(Bi } } -func (hc *hookController) HandleAdmissionEvent(event AdmissionEvent, createTasksFn func(BindingExecutionInfo)) { +func (hc *HookController) HandleAdmissionEvent(event AdmissionEvent, createTasksFn func(BindingExecutionInfo)) { if hc.AdmissionController == nil { return } @@ -214,17 +214,17 @@ func (hc *hookController) HandleAdmissionEvent(event AdmissionEvent, createTasks } } -func (hc *hookController) HandleConversionEvent(event conversion.Event, rule conversion.Rule, createTasksFn func(BindingExecutionInfo)) { +func (hc *HookController) HandleConversionEvent(crdName string, event *v1.ConversionReview, rule conversion.Rule, createTasksFn func(BindingExecutionInfo)) { if hc.ConversionController == nil { return } - execInfo := hc.ConversionController.HandleEvent(event, rule) + execInfo := hc.ConversionController.HandleEvent(crdName, event, rule) if createTasksFn != nil { createTasksFn(execInfo) } } -func (hc *hookController) HandleScheduleEvent(crontab string, createTasksFn func(BindingExecutionInfo)) { +func (hc *HookController) HandleScheduleEvent(crontab string, createTasksFn func(BindingExecutionInfo)) { if hc.ScheduleController == nil { return } @@ -237,51 +237,51 @@ func (hc *hookController) HandleScheduleEvent(crontab string, createTasksFn func } } -func (hc *hookController) UnlockKubernetesEvents() { +func (hc *HookController) UnlockKubernetesEvents() { if hc.KubernetesController != nil { hc.KubernetesController.UnlockEvents() } } -func (hc *hookController) UnlockKubernetesEventsFor(monitorID string) { +func (hc *HookController) UnlockKubernetesEventsFor(monitorID string) { if hc.KubernetesController != nil { hc.KubernetesController.UnlockEventsFor(monitorID) } } -func (hc *hookController) StopMonitors() { +func (hc *HookController) StopMonitors() { if hc.KubernetesController != nil { hc.KubernetesController.StopMonitors() } } -func (hc *hookController) UpdateMonitor(monitorId string, kind, apiVersion string) error { +func (hc *HookController) UpdateMonitor(monitorId string, kind, apiVersion string) error { if hc.KubernetesController != nil { return hc.KubernetesController.UpdateMonitor(monitorId, kind, apiVersion) } return nil } -func (hc *hookController) EnableScheduleBindings() { +func (hc *HookController) EnableScheduleBindings() { if hc.ScheduleController != nil { hc.ScheduleController.EnableScheduleBindings() } } -func (hc *hookController) DisableScheduleBindings() { +func (hc *HookController) DisableScheduleBindings() { if hc.ScheduleController != nil { hc.ScheduleController.DisableScheduleBindings() } } -func (hc *hookController) EnableAdmissionBindings() { +func (hc *HookController) EnableAdmissionBindings() { if hc.AdmissionController != nil { hc.AdmissionController.EnableValidatingBindings() hc.AdmissionController.EnableMutatingBindings() } } -func (hc *hookController) EnableConversionBindings() { +func (hc *HookController) EnableConversionBindings() { if hc.ConversionController != nil { hc.ConversionController.EnableConversionBindings() } @@ -289,7 +289,7 @@ func (hc *hookController) EnableConversionBindings() { // KubernetesSnapshots returns a 'full snapshot': all snapshots for all registered kubernetes bindings. // Note: no caching as in UpdateSnapshots because KubernetesSnapshots used for non-combined binding contexts. -func (hc *hookController) KubernetesSnapshots() map[string][]ObjectAndFilterResult { +func (hc *HookController) KubernetesSnapshots() map[string][]ObjectAndFilterResult { if hc.KubernetesController != nil { return hc.KubernetesController.Snapshots() } @@ -297,8 +297,8 @@ func (hc *hookController) KubernetesSnapshots() map[string][]ObjectAndFilterResu } // getIncludeSnapshotsFrom returns binding names from 'includeSnapshotsFrom' field. -func (hc *hookController) getIncludeSnapshotsFrom(bindingType BindingType, bindingName string) []string { - includeSnapshotsFrom := []string{} +func (hc *HookController) getIncludeSnapshotsFrom(bindingType BindingType, bindingName string) []string { + includeSnapshotsFrom := make([]string, 0) switch bindingType { case OnKubernetesEvent: @@ -348,7 +348,7 @@ func (hc *hookController) getIncludeSnapshotsFrom(bindingType BindingType, bindi // Combined "Synchronization" binging contexts or "Synchronization" // with self-inclusion may require several calls to Snapshot*() methods, but objects // may change between these calls. -func (hc *hookController) UpdateSnapshots(context []BindingContext) []BindingContext { +func (hc *HookController) UpdateSnapshots(context []BindingContext) []BindingContext { if hc.KubernetesController == nil { return context } @@ -356,7 +356,7 @@ func (hc *hookController) UpdateSnapshots(context []BindingContext) []BindingCon // Cache retrieved snapshots to make them consistent. cache := make(map[string][]ObjectAndFilterResult) - newContext := []BindingContext{} + newContext := make([]BindingContext, 0) for _, bc := range context { newBc := bc @@ -389,7 +389,7 @@ func (hc *hookController) UpdateSnapshots(context []BindingContext) []BindingCon return newContext } -func (hc *hookController) SnapshotsInfo() []string { +func (hc *HookController) SnapshotsInfo() []string { if hc.KubernetesController == nil { return []string{"no kubernetes bindings for hook"} } @@ -397,7 +397,7 @@ func (hc *hookController) SnapshotsInfo() []string { return hc.KubernetesController.SnapshotsInfo() } -func (hc *hookController) SnapshotsDump() map[string]interface{} { +func (hc *HookController) SnapshotsDump() map[string]interface{} { if hc.KubernetesController == nil { return nil } diff --git a/pkg/hook/hook.go b/pkg/hook/hook.go index e0001f0a..4cdf702a 100644 --- a/pkg/hook/hook.go +++ b/pkg/hook/hook.go @@ -40,7 +40,7 @@ type Hook struct { Path string // The absolute path to the executable file. Config *config.HookConfig - HookController controller.HookController + HookController *controller.HookController RateLimiter *rate.Limiter TmpDir string @@ -77,7 +77,7 @@ func (h *Hook) RateLimitWait(ctx context.Context) error { return h.RateLimiter.Wait(ctx) } -func (h *Hook) WithHookController(hookController controller.HookController) { +func (h *Hook) WithHookController(hookController *controller.HookController) { h.HookController = hookController } diff --git a/pkg/hook/hook_manager.go b/pkg/hook/hook_manager.go index 6c723dbd..b2dcad62 100644 --- a/pkg/hook/hook_manager.go +++ b/pkg/hook/hook_manager.go @@ -9,6 +9,7 @@ import ( "strings" log "github.com/sirupsen/logrus" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "github.com/flant/shell-operator/pkg/executor" "github.com/flant/shell-operator/pkg/hook/controller" @@ -22,23 +23,7 @@ import ( "github.com/flant/shell-operator/pkg/webhook/conversion" ) -type HookManager interface { - Init() error - Run() - WorkingDir() string - TempDir() string - GetHook(name string) *Hook - GetHookNames() []string - GetHooksInOrder(bindingType BindingType) ([]string, error) - HandleKubeEvent(kubeEvent KubeEvent, createTaskFn func(*Hook, controller.BindingExecutionInfo)) - HandleScheduleEvent(crontab string, createTaskFn func(*Hook, controller.BindingExecutionInfo)) - HandleAdmissionEvent(event AdmissionEvent, createTaskFn func(*Hook, controller.BindingExecutionInfo)) - DetectAdmissionEventType(event AdmissionEvent) BindingType - HandleConversionEvent(event conversion.Event, rule conversion.Rule, createTaskFn func(*Hook, controller.BindingExecutionInfo)) - FindConversionChain(crdName string, rule conversion.Rule) []conversion.Rule -} - -type hookManager struct { +type Manager struct { // dependencies workingDir string tempDir string @@ -59,11 +44,8 @@ type hookManager struct { conversionChains *conversion.ChainStorage } -// hookManager should implement HookManager -var _ HookManager = &hookManager{} - -// HookManagerConfig sets configuration for HookManager -type HookManagerConfig struct { +// ManagerConfig sets configuration for Manager +type ManagerConfig struct { WorkingDir string TempDir string Kmgr kube_events_manager.KubeEventsManager @@ -72,8 +54,8 @@ type HookManagerConfig struct { Cmgr *conversion.WebhookManager } -func NewHookManager(config *HookManagerConfig) *hookManager { - return &hookManager{ +func NewHookManager(config *ManagerConfig) *Manager { + return &Manager{ hooksByName: make(map[string]*Hook), hookNamesInOrder: make([]string, 0), hooksInOrder: make(map[BindingType][]*Hook), @@ -88,16 +70,16 @@ func NewHookManager(config *HookManagerConfig) *hookManager { } } -func (hm *hookManager) WorkingDir() string { +func (hm *Manager) WorkingDir() string { return hm.workingDir } -func (hm *hookManager) TempDir() string { +func (hm *Manager) TempDir() string { return hm.tempDir } // Init finds executables in WorkingDir, execute them with --config argument and add them into indices. -func (hm *hookManager) Init() error { +func (hm *Manager) Init() error { log.Info("Initialize hooks manager. Search for and load all hooks.") hm.hooksInOrder = make(map[BindingType][]*Hook) @@ -140,7 +122,7 @@ func (hm *hookManager) Init() error { } // TODO move --config execution to a Hook method -func (hm *hookManager) loadHook(hookPath string) (hook *Hook, err error) { +func (hm *Manager) loadHook(hookPath string) (hook *Hook, err error) { hookName, err := filepath.Rel(hm.workingDir, hookPath) if err != nil { return nil, err @@ -152,7 +134,7 @@ func (hm *hookManager) loadHook(hookPath string) (hook *Hook, err error) { hookEntry.Infof("Load config from '%s'", hookPath) - envs := []string{} + envs := make([]string, 0) configOutput, err := hm.execCommandOutput(hook.Name, hm.workingDir, hookPath, envs, []string{"--config"}) if err != nil { hookEntry.Errorf("Hook config output:\n%s", string(configOutput)) @@ -221,7 +203,7 @@ func (hm *hookManager) loadHook(hookPath string) (hook *Hook, err error) { return hook, nil } -func (hm *hookManager) execCommandOutput(hookName string, dir string, entrypoint string, envs []string, args []string) ([]byte, error) { +func (hm *Manager) execCommandOutput(hookName string, dir string, entrypoint string, envs []string, args []string) ([]byte, error) { envs = append(os.Environ(), envs...) cmd := executor.MakeCommand(dir, entrypoint, args, envs) cmd.Stdout = nil @@ -242,12 +224,7 @@ func (hm *hookManager) execCommandOutput(hookName string, dir string, entrypoint return output, nil } -// HookManager has no events for now. -func (hm *hookManager) Run() { - panic("implement me") -} - -func (hm *hookManager) GetHook(name string) *Hook { +func (hm *Manager) GetHook(name string) *Hook { hook, exists := hm.hooksByName[name] if exists { return hook @@ -256,11 +233,11 @@ func (hm *hookManager) GetHook(name string) *Hook { return nil } -func (hm *hookManager) GetHookNames() []string { +func (hm *Manager) GetHookNames() []string { return hm.hookNamesInOrder } -func (hm *hookManager) GetHooksInOrder(bindingType BindingType) ([]string, error) { +func (hm *Manager) GetHooksInOrder(bindingType BindingType) ([]string, error) { hooks, ok := hm.hooksInOrder[bindingType] if !ok { return []string{}, nil @@ -288,7 +265,7 @@ func (hm *hookManager) GetHooksInOrder(bindingType BindingType) ([]string, error return hooksNames, nil } -func (hm *hookManager) HandleKubeEvent(kubeEvent KubeEvent, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { +func (hm *Manager) HandleKubeEvent(kubeEvent KubeEvent, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { kubeHooks, _ := hm.GetHooksInOrder(OnKubernetesEvent) for _, hookName := range kubeHooks { @@ -304,7 +281,7 @@ func (hm *hookManager) HandleKubeEvent(kubeEvent KubeEvent, createTaskFn func(*H } } -func (hm *hookManager) HandleScheduleEvent(crontab string, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { +func (hm *Manager) HandleScheduleEvent(crontab string, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { schHooks, _ := hm.GetHooksInOrder(Schedule) for _, hookName := range schHooks { h := hm.GetHook(hookName) @@ -318,7 +295,7 @@ func (hm *hookManager) HandleScheduleEvent(crontab string, createTaskFn func(*Ho } } -func (hm *hookManager) HandleAdmissionEvent(event AdmissionEvent, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { +func (hm *Manager) HandleAdmissionEvent(event AdmissionEvent, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { vHooks, _ := hm.GetHooksInOrder(KubernetesValidating) for _, hookName := range vHooks { h := hm.GetHook(hookName) @@ -344,7 +321,7 @@ func (hm *hookManager) HandleAdmissionEvent(event AdmissionEvent, createTaskFn f } } -func (hm *hookManager) DetectAdmissionEventType(event AdmissionEvent) BindingType { +func (hm *Manager) DetectAdmissionEventType(event AdmissionEvent) BindingType { vHooks, _ := hm.GetHooksInOrder(KubernetesValidating) for _, hookName := range vHooks { h := hm.GetHook(hookName) @@ -366,13 +343,13 @@ func (hm *hookManager) DetectAdmissionEventType(event AdmissionEvent) BindingTyp } // HandleConversionEvent receives a crdName and calculates a sequence of hooks to run. -func (hm *hookManager) HandleConversionEvent(event conversion.Event, rule conversion.Rule, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { +func (hm *Manager) HandleConversionEvent(crdName string, event *v1.ConversionReview, rule conversion.Rule, createTaskFn func(*Hook, controller.BindingExecutionInfo)) { vHooks, _ := hm.GetHooksInOrder(KubernetesConversion) for _, hookName := range vHooks { h := hm.GetHook(hookName) - if h.HookController.CanHandleConversionEvent(event, rule) { - h.HookController.HandleConversionEvent(event, rule, func(info controller.BindingExecutionInfo) { + if h.HookController.CanHandleConversionEvent(crdName, event, rule) { + h.HookController.HandleConversionEvent(crdName, event, rule, func(info controller.BindingExecutionInfo) { if createTaskFn != nil { createTaskFn(h, info) } @@ -381,7 +358,7 @@ func (hm *hookManager) HandleConversionEvent(event conversion.Event, rule conver } } -func (hm *hookManager) UpdateConversionChains() error { +func (hm *Manager) UpdateConversionChains() error { vHooks, _ := hm.GetHooksInOrder(KubernetesConversion) // Update conversionChains. @@ -400,6 +377,6 @@ func (hm *hookManager) UpdateConversionChains() error { return nil } -func (hm *hookManager) FindConversionChain(crdName string, rule conversion.Rule) []conversion.Rule { +func (hm *Manager) FindConversionChain(crdName string, rule conversion.Rule) []conversion.Rule { return hm.conversionChains.FindConversionChain(crdName, rule) } diff --git a/pkg/hook/hook_manager_test.go b/pkg/hook/hook_manager_test.go index 0067eed9..3981f522 100644 --- a/pkg/hook/hook_manager_test.go +++ b/pkg/hook/hook_manager_test.go @@ -15,7 +15,7 @@ import ( "github.com/flant/shell-operator/pkg/webhook/conversion" ) -func newHookManager(t *testing.T, testdataDir string) *hookManager { +func newHookManager(t *testing.T, testdataDir string) *Manager { hooksDir, _ := filepath.Abs(testdataDir) conversionManager := conversion.NewWebhookManager() @@ -24,7 +24,7 @@ func newHookManager(t *testing.T, testdataDir string) *hookManager { admissionManager := admission.NewWebhookManager(nil) admissionManager.Settings = app.ValidatingWebhookSettings - cfg := &HookManagerConfig{ + cfg := &ManagerConfig{ WorkingDir: hooksDir, TempDir: t.TempDir(), Kmgr: nil, diff --git a/pkg/metric_storage/vault/collector.go b/pkg/metric_storage/vault/collector.go index 2aadfa49..77c071d5 100644 --- a/pkg/metric_storage/vault/collector.go +++ b/pkg/metric_storage/vault/collector.go @@ -160,7 +160,6 @@ func (c *ConstCounterCollector) UpdateLabels(labels []string) { } else { newCollection[hash] = c.collection[hash] } - } c.collection = newCollection } @@ -286,7 +285,6 @@ func (c *ConstGaugeCollector) UpdateLabels(labels []string) { } else { newCollection[hash] = c.collection[hash] } - } c.collection = newCollection } diff --git a/pkg/shell-operator/bootstrap.go b/pkg/shell-operator/bootstrap.go index c6d456ec..4ae1fef9 100644 --- a/pkg/shell-operator/bootstrap.go +++ b/pkg/shell-operator/bootstrap.go @@ -181,7 +181,7 @@ func (op *ShellOperator) setupHookManagers(hooksDir string, tempDir string) { op.ConversionWebhookManager.Namespace = app.Namespace // Initialize Hook manager. - cfg := &hook.HookManagerConfig{ + cfg := &hook.ManagerConfig{ WorkingDir: hooksDir, TempDir: tempDir, Kmgr: op.KubeEventsManager, diff --git a/pkg/shell-operator/operator.go b/pkg/shell-operator/operator.go index 555bfd89..d6d0b7c9 100644 --- a/pkg/shell-operator/operator.go +++ b/pkg/shell-operator/operator.go @@ -7,6 +7,7 @@ import ( "github.com/gofrs/uuid/v5" log "github.com/sirupsen/logrus" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" klient "github.com/flant/kube-client/client" "github.com/flant/shell-operator/pkg/hook" @@ -51,7 +52,7 @@ type ShellOperator struct { ManagerEventsHandler *ManagerEventsHandler - HookManager hook.HookManager + HookManager *hook.Manager AdmissionWebhookManager *admission.WebhookManager ConversionWebhookManager *conversion.WebhookManager @@ -296,31 +297,31 @@ func (op *ShellOperator) initConversionWebhookManager() (err error) { } // conversionEventHandler is called when Kubernetes requests a conversion. -func (op *ShellOperator) conversionEventHandler(event conversion.Event) (*conversion.Response, error) { +func (op *ShellOperator) conversionEventHandler(crdName string, review *v1.ConversionReview) (*conversion.Response, error) { logLabels := map[string]string{ "event.id": uuid.Must(uuid.NewV4()).String(), "binding": string(KubernetesConversion), } logEntry := log.WithFields(utils.LabelsToLogFields(logLabels)) - sourceVersions := conversion.ExtractAPIVersions(event.Objects) - logEntry.Infof("Handle '%s' event for crd/%s: %d objects with versions %v", string(KubernetesConversion), event.CrdName, len(event.Objects), sourceVersions) + sourceVersions := conversion.ExtractAPIVersions(review.Request.Objects) + logEntry.Infof("Handle '%s' event for crd/%s: %d objects with version %v", string(KubernetesConversion), crdName, len(review.Request.Objects), sourceVersions) done := false for _, srcVer := range sourceVersions { rule := conversion.Rule{ FromVersion: srcVer, - ToVersion: event.Review.Request.DesiredAPIVersion, + ToVersion: review.Request.DesiredAPIVersion, } - convPath := op.HookManager.FindConversionChain(event.CrdName, rule) + convPath := op.HookManager.FindConversionChain(crdName, rule) if len(convPath) == 0 { continue } logEntry.Infof("Find conversion path for %s: %v", rule.String(), convPath) - for _, rule := range convPath { - var tasks []task.Task - op.HookManager.HandleConversionEvent(event, rule, func(hook *hook.Hook, info controller.BindingExecutionInfo) { + for _, convRule := range convPath { + var convTask task.Task + op.HookManager.HandleConversionEvent(crdName, review, convRule, func(hook *hook.Hook, info controller.BindingExecutionInfo) { newTask := task.NewTask(HookRun). WithMetadata(HookMetadata{ HookName: hook.Name, @@ -331,28 +332,19 @@ func (op *ShellOperator) conversionEventHandler(event conversion.Event) (*conver Group: info.Group, }). WithLogLabels(logLabels) - tasks = append(tasks, newTask) + convTask = newTask }) - // Assert exactly one task is created. - if len(tasks) == 0 { - logEntry.Errorf("Possible bug!!! No hook found for '%s' event for crd/%s", string(KubernetesConversion), event.CrdName) - return nil, fmt.Errorf("no hook found for '%s' event for crd/%s", string(KubernetesConversion), event.CrdName) - } - if len(tasks) > 1 { - logEntry.Errorf("Possible bug!!! %d hooks found for '%s' event for crd/%s", len(tasks), string(KubernetesValidating), event.CrdName) - } - - res := op.taskHandler(tasks[0]) + res := op.taskHandler(convTask) if res.Status == "Fail" { return &conversion.Response{ - FailedMessage: fmt.Sprintf("Hook failed to convert to %s", event.Review.Request.DesiredAPIVersion), + FailedMessage: fmt.Sprintf("Hook failed to convert to %s", review.Request.DesiredAPIVersion), ConvertedObjects: nil, }, nil } - prop := tasks[0].GetProp("conversionResponse") + prop := convTask.GetProp("conversionResponse") response, ok := prop.(*conversion.Response) if !ok { logEntry.Errorf("'conversionResponse' task prop is not of type *conversion.Response: %T", prop) @@ -360,13 +352,13 @@ func (op *ShellOperator) conversionEventHandler(event conversion.Event) (*conver } // Set response objects as new objects for a next round. - event.Objects = response.ConvertedObjects + review.Request.Objects = response.ConvertedObjects // Stop iterating if hook has converted all objects to a desiredAPIVersions. - newSourceVersions := conversion.ExtractAPIVersions(event.Objects) + newSourceVersions := conversion.ExtractAPIVersions(review.Request.Objects) // logEntry.Infof("Hook return conversion response: failMsg=%s, %d convertedObjects, versions:%v, desired: %s", response.FailedMessage, len(response.ConvertedObjects), newSourceVersions, event.Review.Request.DesiredAPIVersion) - if len(newSourceVersions) == 1 && newSourceVersions[0] == event.Review.Request.DesiredAPIVersion { + if len(newSourceVersions) == 1 && newSourceVersions[0] == review.Request.DesiredAPIVersion { // success done = true break @@ -380,12 +372,12 @@ func (op *ShellOperator) conversionEventHandler(event conversion.Event) (*conver if done { return &conversion.Response{ - ConvertedObjects: event.Objects, + ConvertedObjects: review.Request.Objects, }, nil } return &conversion.Response{ - FailedMessage: fmt.Sprintf("Conversion to %s was not successuful", event.Review.Request.DesiredAPIVersion), + FailedMessage: fmt.Sprintf("Conversion to %s was not successuful", review.Request.DesiredAPIVersion), }, nil } diff --git a/pkg/utils/file/file.go b/pkg/utils/file/file.go index e6d7f581..479564fd 100644 --- a/pkg/utils/file/file.go +++ b/pkg/utils/file/file.go @@ -84,7 +84,6 @@ func RecursiveCheckLibDirectory(dir string) error { return nil }) - if err != nil { return err } diff --git a/pkg/utils/file/file_test.go b/pkg/utils/file/file_test.go index c26363e2..a4abf821 100644 --- a/pkg/utils/file/file_test.go +++ b/pkg/utils/file/file_test.go @@ -17,12 +17,12 @@ func prepareTestDirTree() (string, error) { return "", fmt.Errorf("error creating temp directory: %v\n", err) } - if err = os.MkdirAll(filepath.Join(tmpDir, "aa"), 0755); err != nil { + if err = os.MkdirAll(filepath.Join(tmpDir, "aa"), 0o755); err != nil { os.RemoveAll(tmpDir) return "", err } - if err = os.MkdirAll(filepath.Join(tmpDir, "lib"), 0755); err != nil { + if err = os.MkdirAll(filepath.Join(tmpDir, "lib"), 0o755); err != nil { os.RemoveAll(tmpDir) return "", err } @@ -49,7 +49,7 @@ func createExecutableFile(file string) error { if _, err := os.Create(file); err != nil { return err } - os.Chmod(file, 0777) + os.Chmod(file, 0o777) return nil } diff --git a/pkg/webhook/conversion/event.go b/pkg/webhook/conversion/event.go index c607d017..dc482d08 100644 --- a/pkg/webhook/conversion/event.go +++ b/pkg/webhook/conversion/event.go @@ -1,26 +1,21 @@ package conversion -import ( - "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" -) - -type Event struct { - CrdName string - Review *v1.ConversionReview - Objects []unstructured.Unstructured -} +// type Event struct { +// CrdName string +// Review *v1.ConversionReview +// Objects []unstructured.Unstructured +//} // Mimic a v1.ConversionReview structure but with the array of unstructured Objects // instead of the array of runtime.RawExtension -func (e Event) GetReview() map[string]interface{} { - return map[string]interface{}{ - "kind": e.Review.Kind, - "apiVersion": e.Review.APIVersion, - "request": map[string]interface{}{ - "uid": e.Review.Request.UID, - "desiredAPIVersion": e.Review.Request.DesiredAPIVersion, - "objects": e.Objects, - }, - } -} +// func (e Event) GetReview() map[string]interface{} { +// return map[string]interface{}{ +// "kind": e.Review.Kind, +// "apiVersion": e.Review.APIVersion, +// "request": map[string]interface{}{ +// "uid": e.Review.Request.UID, +// "desiredAPIVersion": e.Review.Request.DesiredAPIVersion, +// "objects": e.Objects, +// }, +// } +//} diff --git a/pkg/webhook/conversion/handler.go b/pkg/webhook/conversion/handler.go index be1eaee7..57aa5c37 100644 --- a/pkg/webhook/conversion/handler.go +++ b/pkg/webhook/conversion/handler.go @@ -12,7 +12,6 @@ import ( log "github.com/sirupsen/logrus" v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" structured_logger "github.com/flant/shell-operator/pkg/utils/structured-logger" @@ -48,105 +47,83 @@ func NewWebhookHandler() *WebhookHandler { func (h *WebhookHandler) serveReviewRequest(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() - bodyBytes, err := io.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte("Error reading request body")) - log.Errorf("Error reading request body: %v", err) - return - } - - conversionResponse, err := h.handleReviewRequest(r.URL.Path, bodyBytes) + conversionResponse, err := h.handleReviewRequest(r.URL.Path, r.Body) if err != nil { w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte(err.Error())) return } + conversionResponse.Request = nil - respBytes, err := json.Marshal(conversionResponse) + w.Header().Set("Content-type", "application/json") + err = json.NewEncoder(w).Encode(conversionResponse) if err != nil { w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte("Error json encoding ConversionReview")) log.Errorf("Error json encoding ConversionReview: %v", err) return } - - w.Header().Set("Content-type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(respBytes) } // See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#write-a-conversion-webhook-server // This code always response with v1 ConversionReview: it works for 1.16+. -func (h *WebhookHandler) handleReviewRequest(path string, body []byte) (*v1.ConversionReview, error) { +func (h *WebhookHandler) handleReviewRequest(path string, body io.Reader) (*v1.ConversionReview, error) { crdName := detectCrdName(path) log.Infof("Got ConversionReview request for crd/%s", crdName) var inReview v1.ConversionReview - err := json.Unmarshal(body, &inReview) + err := json.NewDecoder(body).Decode(&inReview) if err != nil { log.Errorf("Error parsing ConversionReview: %v", err) - return nil, fmt.Errorf("fail to parse ConversionReview") + return nil, fmt.Errorf("fail to parse ConversionReview: %w", err) } - review := &v1.ConversionReview{ - TypeMeta: inReview.TypeMeta, - Response: &v1.ConversionResponse{ - UID: inReview.Request.UID, - }, + if inReview.Request == nil { + return nil, fmt.Errorf("conversion request is nil") } + inReview.Response.UID = inReview.Request.UID + if h.Manager.EventHandlerFn == nil { - review.Response.Result = metav1.Status{ + inReview.Response.Result = metav1.Status{ Status: "Failed", Message: "ConversionReview handler is not defined", } - return review, nil - } - - event, err := prepareConversionEvent(crdName, &inReview) - if err != nil { - return nil, err + return &inReview, nil } - conversionResponse, err := h.Manager.EventHandlerFn(event) + conversionResponse, err := h.Manager.EventHandlerFn(crdName, &inReview) if err != nil { - review.Response.Result = metav1.Status{ + inReview.Response.Result = metav1.Status{ Status: "Failed", Message: err.Error(), } - return review, nil + return &inReview, nil } if conversionResponse.FailedMessage != "" { - review.Response.Result = metav1.Status{ + inReview.Response.Result = metav1.Status{ Status: "Failed", Message: conversionResponse.FailedMessage, } - return review, nil + return &inReview, nil } if len(inReview.Request.Objects) != len(conversionResponse.ConvertedObjects) { - review.Response.Result = metav1.Status{ + inReview.Response.Result = metav1.Status{ Status: "Failed", - Message: fmt.Sprintf("Hook returned %d objects instead of %d", len(conversionResponse.ConvertedObjects), len(review.Request.Objects)), + Message: fmt.Sprintf("Hook returned %d objects instead of %d", len(conversionResponse.ConvertedObjects), len(inReview.Request.Objects)), } - return review, nil + return &inReview, nil } - review.Response.Result = metav1.Status{ + inReview.Response.Result = metav1.Status{ Status: "Success", } - // Convert objects from hook into to array of runtime.RawExtension - rawObjects := make([]runtime.RawExtension, len(conversionResponse.ConvertedObjects)) - for i, obj := range conversionResponse.ConvertedObjects { - tmpObj := obj - rawObjects[i] = runtime.RawExtension{Object: &tmpObj} - } - review.Response.ConvertedObjects = rawObjects + inReview.Response.ConvertedObjects = conversionResponse.ConvertedObjects - return review, nil + return &inReview, nil } // detectCrdName extracts crdName from the url path. @@ -154,37 +131,20 @@ func detectCrdName(path string) string { return strings.TrimPrefix(path, "/") } -func prepareConversionEvent(crdName string, review *v1.ConversionReview) (event Event, err error) { - event.CrdName = crdName - event.Review = review - event.Objects, err = rawExtensionToUnstructured(review.Request.Objects) - return event, err -} - -func ExtractAPIVersions(objs []unstructured.Unstructured) []string { - verMap := map[string]bool{} - for _, obj := range objs { - verMap[obj.GetAPIVersion()] = true - } +func ExtractAPIVersions(objs []runtime.RawExtension) []string { + verMap := make(map[string]struct{}) res := make([]string, 0) - for ver := range verMap { - res = append(res, ver) - } - return res -} - -func rawExtensionToUnstructured(objects []runtime.RawExtension) ([]unstructured.Unstructured, error) { - res := make([]unstructured.Unstructured, 0) - for _, obj := range objects { - cr := unstructured.Unstructured{} + for _, obj := range objs { + version := obj.Object.GetObjectKind().GroupVersionKind().GroupVersion().String() - if err := cr.UnmarshalJSON(obj.Raw); err != nil { - return nil, fmt.Errorf("failed to unmarshall object in conversion request with error: %v", err) + if _, ok := verMap[version]; ok { + continue } - res = append(res, cr) + verMap[version] = struct{}{} + res = append(res, version) } - return res, nil + return res } diff --git a/pkg/webhook/conversion/manager.go b/pkg/webhook/conversion/manager.go index 8fd3a606..e76e5cc1 100644 --- a/pkg/webhook/conversion/manager.go +++ b/pkg/webhook/conversion/manager.go @@ -2,15 +2,15 @@ package conversion import ( "context" - "os" - log "github.com/sirupsen/logrus" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "os" klient "github.com/flant/kube-client/client" "github.com/flant/shell-operator/pkg/webhook/server" ) -type EventHandlerFn func(event Event) (*Response, error) +type EventHandlerFn func(cdrName string, review *v1.ConversionReview) (*Response, error) // WebhookManager is a public interface to be used from operator.go. // diff --git a/pkg/webhook/conversion/response.go b/pkg/webhook/conversion/response.go index 40c1f1a5..ce0188f3 100644 --- a/pkg/webhook/conversion/response.go +++ b/pkg/webhook/conversion/response.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" ) /* @@ -37,8 +37,8 @@ ConvertedObjects: # All other changes to metadata fields by the webhook are ignored. */ type Response struct { - FailedMessage string `json:"failedMessage"` - ConvertedObjects []unstructured.Unstructured `json:"convertedObjects,omitempty"` + FailedMessage string `json:"failedMessage"` + ConvertedObjects []runtime.RawExtension `json:"convertedObjects,omitempty"` } func ResponseFromFile(filePath string) (*Response, error) { diff --git a/test/hook/context/context_combiner.go b/test/hook/context/context_combiner.go index a9bfc35b..62b30f25 100644 --- a/test/hook/context/context_combiner.go +++ b/test/hook/context/context_combiner.go @@ -71,7 +71,7 @@ func (c *ContextCombiner) Combined() []binding_context.BindingContext { return bc } -func (c *ContextCombiner) CombinedAndUpdated(hookCtrl controller.HookController) (GeneratedBindingContexts, error) { +func (c *ContextCombiner) CombinedAndUpdated(hookCtrl *controller.HookController) (GeneratedBindingContexts, error) { bc := c.Combined() bc = hookCtrl.UpdateSnapshots(bc) return ConvertToGeneratedBindingContexts(bc) diff --git a/test/hook/context/generator.go b/test/hook/context/generator.go index e6803cce..ce4b56c1 100644 --- a/test/hook/context/generator.go +++ b/test/hook/context/generator.go @@ -28,7 +28,7 @@ type GeneratedBindingContexts struct { type BindingContextController struct { Hook *hook.Hook - HookCtrl controller.HookController + HookCtrl *controller.HookController HookMap map[string]string HookConfig string @@ -86,9 +86,6 @@ func (b *BindingContextController) RegisterCRD(group, version, kind string, name // Run generates binding contexts for hook tests func (b *BindingContextController) Run(initialState string) (GeneratedBindingContexts, error) { - // fmt.Println("Run start") - // defer func() { fmt.Println("Run end") }() - b.mu.Lock() defer b.mu.Unlock()