diff --git a/compose/rest/automation.go b/compose/rest/automation.go index 4040152d7..3dd746b17 100644 --- a/compose/rest/automation.go +++ b/compose/rest/automation.go @@ -48,5 +48,5 @@ func (ctrl *Automation) Bundle(ctx context.Context, r *request.AutomationBundle) } func (ctrl *Automation) TriggerScript(ctx context.Context, r *request.AutomationTriggerScript) (interface{}, error) { - return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.ComposeOnManual()) + return resputil.OK(), corredor.Service().Exec(ctx, r.Script, event.ComposeOnManual()) } diff --git a/compose/rest/module.go b/compose/rest/module.go index 71f8d400f..b2462b671 100644 --- a/compose/rest/module.go +++ b/compose/rest/module.go @@ -151,7 +151,7 @@ func (ctrl *Module) TriggerScript(ctx context.Context, r *request.ModuleTriggerS } // @todo implement same behaviour as we have on record - module+oldModule - err = corredor.Service().ExecOnManual(ctx, r.Script, event.ModuleOnManual(module, module, namespace)) + err = corredor.Service().Exec(ctx, r.Script, event.ModuleOnManual(module, module, namespace)) return ctrl.makePayload(ctx, module, err) } diff --git a/compose/rest/namespace.go b/compose/rest/namespace.go index 5075db59f..5f37a958a 100644 --- a/compose/rest/namespace.go +++ b/compose/rest/namespace.go @@ -131,7 +131,7 @@ func (ctrl *Namespace) TriggerScript(ctx context.Context, r *request.NamespaceTr return } - err = corredor.Service().ExecOnManual(ctx, r.Script, event.NamespaceOnManual(namespace, nil)) + err = corredor.Service().Exec(ctx, r.Script, event.NamespaceOnManual(namespace, nil)) return ctrl.makePayload(ctx, namespace, err) } diff --git a/compose/rest/page.go b/compose/rest/page.go index 02eb0f995..cc2082c9c 100644 --- a/compose/rest/page.go +++ b/compose/rest/page.go @@ -172,7 +172,7 @@ func (ctrl *Page) TriggerScript(ctx context.Context, r *request.PageTriggerScrip } // @todo implement same behaviour as we have on record - page+oldPage - err = corredor.Service().ExecOnManual(ctx, r.Script, event.PageOnManual(page, page, namespace)) + err = corredor.Service().Exec(ctx, r.Script, event.PageOnManual(page, page, namespace)) return ctrl.makePayload(ctx, page, err) } diff --git a/compose/rest/record.go b/compose/rest/record.go index 8aa8fe64c..9da4dac19 100644 --- a/compose/rest/record.go +++ b/compose/rest/record.go @@ -426,7 +426,7 @@ func (ctrl *Record) TriggerScript(ctx context.Context, r *request.RecordTriggerS record.Values = values.Sanitizer().Run(module, r.Values) validated := values.Validator().Run(module, record) - err = corredor.Service().ExecOnManual( + err = corredor.Service().Exec( ctx, r.Script, event.RecordOnManual(record, oldRecord, module, namespace, validated), diff --git a/pkg/corredor/service.go b/pkg/corredor/service.go index dd92a7b76..17f557153 100644 --- a/pkg/corredor/service.go +++ b/pkg/corredor/service.go @@ -25,13 +25,13 @@ type ( // for when we're doing lazy setup opt options.CorredorOpt - // list of all registered triggers + // list of all registered event handlers // map[] registered map[string][]uintptr - // list of all registered onManual triggers & scripts + // list of all registered explicitly executable script // map[][] = true - manual map[string]map[string]bool + explicit map[string]map[string]bool // Combined list of client and server scripts sScripts ScriptSet @@ -58,7 +58,7 @@ type ( permissions permissions.RuleSet } - Event interface { + ScriptArgs interface { eventbus.Event // Encode (event) to arguments passed to @@ -123,7 +123,7 @@ func NewService(logger *zap.Logger, opt options.CorredorOpt) *service { opt: opt, registered: make(map[string][]uintptr), - manual: make(map[string]map[string]bool), + explicit: make(map[string]map[string]bool), authTokenMaker: auth.DefaultJwtHandler, eventRegistry: eventbus.Service(), @@ -239,36 +239,30 @@ func (svc service) makeScriptFilter(ctx context.Context, f Filter) func(s *Scrip } } -// ExecOnManual verifies permissions, event and script and sends exec request to corredor -func (svc service) ExecOnManual(ctx context.Context, scriptName string, event Event) (err error) { +// Exec verifies permissions, event and script and sends exec request to corredor +func (svc service) Exec(ctx context.Context, scriptName string, args ScriptArgs) (err error) { if !svc.opt.Enabled { return } var ( - res = event.ResourceType() - evt = event.EventType() - + res = args.ResourceType() script *Script ok bool runAs string ) - if onManualEventType != evt { - return errors.Errorf("triggered event type is not onManual (%q)", evt) - } - if len(scriptName) == 0 { return errors.Errorf("script name not provided (%q)", scriptName) } - if _, ok = svc.manual[scriptName]; !ok { - return errors.Errorf("unregistered onManual script %q", scriptName) + if _, ok = svc.explicit[scriptName]; !ok { + return errors.Errorf("unregistered explicit script %q", scriptName) } - if _, ok = svc.manual[scriptName][res]; !ok { - return errors.Errorf("unregistered onManual script %q for resource %q", scriptName, res) + if _, ok = svc.explicit[scriptName][res]; !ok { + return errors.Errorf("unregistered explicit script %q for resource %q", scriptName, res) } if script = svc.sScripts.FindByName(scriptName); script == nil { @@ -279,10 +273,17 @@ func (svc service) ExecOnManual(ctx context.Context, scriptName string, event Ev return errors.Errorf("permission to execute %s denied", scriptName) } - return svc.exec(ctx, scriptName, runAs, event) + if script.Security != nil { + runAs = script.Security.RunAs + } + + return svc.exec(ctx, scriptName, runAs, args) } // Can current user execute this script +// +// This is used only in case of explicit execution (onManual) and never when +// scripts are executed implicitly (deferred, before/after...) func (svc service) canExec(ctx context.Context, script string) bool { u := auth.GetIdentityFromContext(ctx) if auth.IsSuperUser(u) { @@ -358,7 +359,7 @@ func (svc *service) registerServerScripts(ss ...*ServerScript) { // Reset indexes svc.registered = make(map[string][]uintptr) - svc.manual = make(map[string]map[string]bool) + svc.explicit = make(map[string]map[string]bool) // Reset security svc.permissions = permissions.RuleSet{} @@ -390,9 +391,7 @@ func (svc *service) registerServerScripts(ss ...*ServerScript) { } if len(s.Errors) == 0 { - - if manual := mapManualTriggers(script); len(manual) > 0 { - + if manual := mapExplicitTriggers(script); len(manual) > 0 { if script.Security != nil { runAs = script.Security.RunAs @@ -417,25 +416,15 @@ func (svc *service) registerServerScripts(ss ...*ServerScript) { svc.permissions = append(svc.permissions, deny...) } - if len(s.Errors) == 0 { - svc.manual[script.Name] = manual - } + svc.explicit[script.Name] = manual } - if len(s.Errors) == 0 { - svc.registered[script.Name] = svc.registerTriggers(script) - } - } + svc.registered[script.Name] = svc.registerTriggers(script) - // Even if there are errors, we'll append the scripts - // because we need to serve them as a list for script management - svc.sScripts = append(svc.sScripts, s) - - if len(s.Errors) == 0 { svc.log.Debug( "script registered", zap.String("script", s.Name), - zap.Int("manual", len(svc.manual[script.Name])), + zap.Int("explicit", len(svc.explicit[script.Name])), zap.Int("triggers", len(svc.registered[script.Name])), ) } else { @@ -465,7 +454,7 @@ func (svc *service) registerTriggers(script *ServerScript) []uintptr { } for i := range script.Triggers { - if ops, err = makeTriggerOpts(script.Triggers[i]); err != nil { + if ops, err = triggerToHandlerOps(script.Triggers[i]); err != nil { log.Warn( "could not make trigger options", zap.Error(err), @@ -480,7 +469,7 @@ func (svc *service) registerTriggers(script *ServerScript) []uintptr { ptr := svc.eventRegistry.Register(func(ctx context.Context, ev eventbus.Event) (err error) { // Is this compatible event? - if ce, ok := ev.(Event); ok { + if ce, ok := ev.(ScriptArgs); ok { // Can only work with corteza compatible events return svc.exec(ctx, script.Name, runAs, ce) } @@ -498,7 +487,7 @@ func (svc *service) registerTriggers(script *ServerScript) []uintptr { // // It does not do any constraints checking - this is the responsibility of the // individual event implemntation -func (svc service) exec(ctx context.Context, script string, runAs string, event Event) (err error) { +func (svc service) exec(ctx context.Context, script string, runAs string, args ScriptArgs) (err error) { var ( requestId = middleware.GetReqID(ctx) @@ -512,14 +501,14 @@ func (svc service) exec(ctx context.Context, script string, runAs string, event log = svc.log.With( zap.String("script", script), zap.String("runAs", runAs), - zap.String("event", event.EventType()), - zap.String("resource", event.ResourceType()), + zap.String("args", args.EventType()), + zap.String("resource", args.ResourceType()), ) ) log.Debug("triggered") - if encodedEvent, err = event.Encode(); err != nil { + if encodedEvent, err = args.Encode(); err != nil { return } @@ -594,11 +583,11 @@ func (svc service) exec(ctx context.Context, script string, runAs string, event // //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// //// // Additional (string) arguments - // basic event/event info - if err = encodeArguments(req.Args, "event", event.EventType()); err != nil { + // basic args/event info + if err = encodeArguments(req.Args, "args", args.EventType()); err != nil { return } - if err = encodeArguments(req.Args, "resource", event.ResourceType()); err != nil { + if err = encodeArguments(req.Args, "resource", args.ResourceType()); err != nil { return } @@ -670,8 +659,8 @@ func (svc service) exec(ctx context.Context, script string, runAs string, event encodedResults[key] = []byte(rsp.Result[key]) } - // Send results back to the event for decoding - err = event.Decode(encodedResults) + // Send results back to the args for decoding + err = args.Decode(encodedResults) if err != nil { log.Debug( "could not decode results", diff --git a/pkg/corredor/service_test.go b/pkg/corredor/service_test.go index 26fdde3a3..aaaf59986 100644 --- a/pkg/corredor/service_test.go +++ b/pkg/corredor/service_test.go @@ -226,17 +226,17 @@ func TestService_canExec(t *testing.T) { a.False(svc.canExec(ctx, script2.Name)) } -func TestService_ExecOnManual(t *testing.T) { +func TestService_Exec(t *testing.T) { var ( a = assert.New(t) svc = &service{ - manual: map[string]map[string]bool{}, - opt: options.CorredorOpt{Enabled: true}, + explicit: map[string]map[string]bool{}, + opt: options.CorredorOpt{Enabled: true}, } ) - a.Error(svc.ExecOnManual(nil, "script", &mockEvent{eType: "not-onManual"})) - a.Error(svc.ExecOnManual(nil, "script", &mockEvent{eType: onManualEventType})) - svc.manual["script"] = nil - a.Error(svc.ExecOnManual(nil, "script", &mockEvent{eType: onManualEventType})) + a.Error(svc.Exec(nil, "script", &mockEvent{eType: "not-onManual"})) + a.Error(svc.Exec(nil, "script", &mockEvent{eType: onManualEventType})) + svc.explicit["script"] = nil + a.Error(svc.Exec(nil, "script", &mockEvent{eType: onManualEventType})) } diff --git a/pkg/corredor/util.go b/pkg/corredor/util.go index a52f173ae..878cf5b0f 100644 --- a/pkg/corredor/util.go +++ b/pkg/corredor/util.go @@ -17,10 +17,9 @@ type ( } ) -// mapManualTriggers removes all manual triggers from the list of script's triggers -// -// and returns a hash map with resources from these manual triggers -func mapManualTriggers(script *ServerScript) map[string]bool { +// mapExplicitTriggers scans for explicit event types from the list of script's triggers +// and returns a hash map with resources from these explicit triggers +func mapExplicitTriggers(script *ServerScript) map[string]bool { var ( hash = make(map[string]bool) ) @@ -30,7 +29,7 @@ func mapManualTriggers(script *ServerScript) map[string]bool { // so let's make a copy we can play with trigger := script.Triggers[i] - if slice.HasString(trigger.EventTypes, onManualEventType) { + if len(slice.IntersectStrings(trigger.EventTypes, explicitEventTypes)) > 0 { for _, res := range trigger.ResourceTypes { hash[res] = true } @@ -52,6 +51,9 @@ func triggerToHandlerOps(t *Trigger) (oo []eventbus.HandlerRegOp, err error) { // Make a copy of event types slice so that we do not modify it types := slice.PluckString(t.EventTypes, onManualEventType) + + // If no other event types are left on the trigger, + // no need for procede if len(types) == 0 && len(t.EventTypes) > 0 { return } diff --git a/pkg/corredor/util_test.go b/pkg/corredor/util_test.go index 356dde8de..139d128bf 100644 --- a/pkg/corredor/util_test.go +++ b/pkg/corredor/util_test.go @@ -17,7 +17,7 @@ func TestMapManualTriggers(t *testing.T) { "r1": true, "r2": true, }, - mapManualTriggers(&ServerScript{ + mapExplicitTriggers(&ServerScript{ Triggers: []*Trigger{&Trigger{ ResourceTypes: []string{"r1", "r2"}, EventTypes: []string{"onTimestamp", onManualEventType, "onInterval"}, @@ -27,7 +27,7 @@ func TestMapManualTriggers(t *testing.T) { a.EqualValues( map[string]bool{}, - mapManualTriggers(&ServerScript{ + mapExplicitTriggers(&ServerScript{ Triggers: []*Trigger{&Trigger{ ResourceTypes: []string{"r1", "r2"}, EventTypes: []string{"onTimestamp", "onInterval"}, diff --git a/system/rest/application.go b/system/rest/application.go index bdb01907f..98d5dcb3a 100644 --- a/system/rest/application.go +++ b/system/rest/application.go @@ -130,7 +130,7 @@ func (ctrl *Application) TriggerScript(ctx context.Context, r *request.Applicati } // @todo implement same behaviour as we have on record - Application+oldApplication - err = corredor.Service().ExecOnManual(ctx, r.Script, event.ApplicationOnManual(application, application)) + err = corredor.Service().Exec(ctx, r.Script, event.ApplicationOnManual(application, application)) return application, err } diff --git a/system/rest/automation.go b/system/rest/automation.go index 52b114bdb..9f525b70e 100644 --- a/system/rest/automation.go +++ b/system/rest/automation.go @@ -48,5 +48,5 @@ func (ctrl *Automation) Bundle(ctx context.Context, r *request.AutomationBundle) } func (ctrl *Automation) TriggerScript(ctx context.Context, r *request.AutomationTriggerScript) (interface{}, error) { - return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.SystemOnManual()) + return resputil.OK(), corredor.Service().Exec(ctx, r.Script, event.SystemOnManual()) } diff --git a/system/rest/role.go b/system/rest/role.go index 30f65ef24..c36111e46 100644 --- a/system/rest/role.go +++ b/system/rest/role.go @@ -186,7 +186,7 @@ func (ctrl *Role) TriggerScript(ctx context.Context, r *request.RoleTriggerScrip } // @todo implement same behaviour as we have on record - role+oldRole - err = corredor.Service().ExecOnManual(ctx, r.Script, event.RoleOnManual(role, role)) + err = corredor.Service().Exec(ctx, r.Script, event.RoleOnManual(role, role)) return role, err } diff --git a/system/rest/user.go b/system/rest/user.go index 1d2b9f390..425da1590 100644 --- a/system/rest/user.go +++ b/system/rest/user.go @@ -142,7 +142,7 @@ func (ctrl *User) TriggerScript(ctx context.Context, r *request.UserTriggerScrip } // @todo implement same behaviour as we have on record - user+oldUser - err = corredor.Service().ExecOnManual(ctx, r.Script, event.UserOnManual(user, user)) + err = corredor.Service().Exec(ctx, r.Script, event.UserOnManual(user, user)) return user, err }