Refactor corredor service and make it less events-oriented
This commit is contained in:
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
+36
-47
@@ -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[<script-name>]
|
||||
registered map[string][]uintptr
|
||||
|
||||
// list of all registered onManual triggers & scripts
|
||||
// list of all registered explicitly executable script
|
||||
// map[<script-name>][<resource>] = 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",
|
||||
|
||||
@@ -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}))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user