Commit ce10e46e authored by Denis Arh's avatar Denis Arh
Browse files

Refactor corredor service and make it less events-oriented

parent 44f818e1
......@@ -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),
......
......@@ -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)
}
}
// 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)
svc.registered[script.Name] = svc.registerTriggers(script)
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())
}
......@@ -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
}
......
......@@ -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
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment