preserve actions list while getting them from callback data (#36)

* preserve actions list while getting them from callback data

* small fixes

Co-authored-by: Dmitry Ng <19asdek91@gmail.com>
This commit is contained in:
Mikhail Kochegarov
2023-01-16 17:47:26 +10:00
committed by GitHub
parent 0e3500583e
commit e26ea21191
3 changed files with 52 additions and 42 deletions
+24 -2
View File
@@ -100,7 +100,7 @@ describe('file_remover agent', function()
"failed to send file remove action")
-- wait for expected result to arrive (in any order)
assert.is_true(__mock:expect("event", function(o)
return o.event and o.event.name == "fr_object_file_removed_failed"
return o.event and o.event.name == "fr_object_file_removed_failed"
end))
assert.is_true(__mock:expect("data",
function(o) return o.data and o.data.name == "fr_remove_object_file" end))
@@ -190,7 +190,8 @@ describe('file_remover agent', function()
file_path = new_test_file()
assert.is_true(file_exists(file_path), "file was not created on FS")
end
local expected_reason = test_case.create_file and "removed successful" or file_path .. ": No such file or directory"
local expected_reason = test_case.create_file and "removed successful" or
file_path .. ": No such file or directory"
local expected_uniq = "fr_" ..
test_case.type ..
"_" .. test_case.subtype ..
@@ -333,6 +334,26 @@ describe('file_remover agent', function()
return false
end))
end)
it('actions list should be preserved in events', function()
local test_file_path = new_test_file(__mock.rand_uuid())
local data = { data = {}, actions = { "some_action" } }
data.data['object.fullpath'] = test_file_path
local action_data = cjson.encode(data)
assert(__mock:send_action(__mock.mock_token, __mock.module_token, action_data, "fr_remove_object_file"))
assert.is_true(__mock:expect("event",
function(o)
if o.event and o.event.name == "fr_object_file_removed_successful" then
assert.not_nil(o.event.actions)
assert.equal(2, #o.event.actions)
assert.equal('some_action', o.event.actions[1])
assert.equal('file_remover.fr_remove_object_file', o.event.actions[2])
return true
end
return false
end))
end)
end)
describe('file removal bug fixes', function()
@@ -355,4 +376,5 @@ describe('file_remover agent', function()
assert.is_false(file_exists(test_file_path), "test file was not removed by a module")
end)
end)
end)
+28 -23
View File
@@ -84,6 +84,8 @@ cmodule.load_dependencies = function()
local fields_schema = __config.get_fields_schema()
local module_info = __config.get_module_info()
cmodule.module_config = cjson.decode(__config.get_current_config()) or {}
cmodule.unload_dependencies()
cmodule.action_engine = CActionEngine(
@@ -102,36 +104,27 @@ cmodule.load_dependencies = function()
cmodule.fields = create_strict_strings_set(cmodule.action_validator.fields_validators, "field")
end
cmodule.push_event_for_action = function(event_name, action_name, event_data, actions)
assert(event_name ~= nil and event_name ~= "", "event name must be defined")
assert(action_name ~= nil and action_name ~= "", "action name must be defined")
event_data = event_data or {}
actions = actions or {}
if action_name ~= "" then
local action_full_name = __config.ctx.name .. "." .. action_name
if glue.indexof(action_full_name, actions) == nil then
table.insert(actions, action_full_name)
end
end
cmodule.push_event(event_name, event_data, actions)
end
cmodule.push_event = function(event_name, event_data, actions)
assert(event_name ~= nil and event_name ~= "", "event name must be defined")
event_data = event_data or {}
actions = actions or {}
local event = {
-- This is small "hack" that fills real event data with actions list that was performed.
-- It is needed to be filled for next modules wol will receive _action_ requests to know
-- what actions was already in a chain and be able to do a circuit break.
event_data.actions = actions
local result, next_actions_list = cmodule.event_engine:push_event({
__module = __config.ctx.name,
name = event_name, data = event_data,
name = event_name,
data = event_data,
actions = actions,
}
local result, actions_list = cmodule.event_engine:push_event(event)
})
-- result value defines if there are actions that need to be executed
-- configuration of the following actions is done in "security policy".
if result then
for action_id, action_result in ipairs(cmodule.action_engine:exec(__aid, actions_list)) do
for action_id, action_result in ipairs(cmodule.action_engine:exec(__aid, next_actions_list)) do
__log.infof("action '%s' was requested and executed with result: %s", action_id, action_result)
end
end
@@ -142,6 +135,8 @@ cmodule.start = function(action_handlers, background_process)
action = function(src, data, action_name)
local action_data = cjson.decode(data) or {}
-- actions is a set of full action names (module_name.acton_name) that was already performed
local actions = action_data.actions or {}
action_data.__cid = action_data.__cid or make_uuid()
@@ -159,6 +154,7 @@ cmodule.start = function(action_handlers, background_process)
response.status = "error"
response.error = error
response.reason = reason
__log.errorf("%s: %s", error, reason)
return __api.send_data_to(src, cjson.encode(response))
end
@@ -166,10 +162,12 @@ cmodule.start = function(action_handlers, background_process)
if action_handler == nil then
response.status = "error"
response.error = protocol.implementation_errors.action_handler_not_defined
__log.errorf("%s: action handler '%s' is not defined", response.error, action_name)
return __api.send_data_to(src, cjson.encode(response))
end
local action_handler_result, event_data = action_handler.handler(action_data.data)
-- handler can mutate actions list if it is required by the business logic
local action_handler_result, event_data = action_handler.handler(action_data.data, actions)
local event_name = action_handler.success
if not action_handler_result then
event_name = action_handler.failure
@@ -178,15 +176,22 @@ cmodule.start = function(action_handlers, background_process)
event_data.__cid = action_data.__cid
event_data.uuid = action_data.uuid or make_uuid()
cmodule.push_event_for_action(event_name, action_name, event_data)
-- before sending the event, take list of actions that was already performed and add current action
local action_full_name = __config.ctx.name .. "." .. action_name
if glue.indexof(action_full_name, actions) == nil then
table.insert(actions, action_full_name)
end
-- try to send an event
cmodule.push_event(event_name, event_data, actions)
response.data = event_data
if action_handler_result then
response.status = "success"
else
response.status = "error"
response.error = protocol.implementation_errors.action_handler_error
response.error = protocol.business_logic_errors.action_handler_error
response.reason = event_data.reason
__log.errorf("%s: %s", response.error, response.reason)
end
return __api.send_data_to(src, cjson.encode(response))
end,
-17
View File
@@ -1,5 +1,4 @@
local cjson = require("cjson.safe")
local glue = require("glue")
local protocol = require("protocol/protocol")
require("engine")
@@ -82,22 +81,6 @@ local function get_agent_src_by_id(id, atype)
return "", {}
end
smodule.push_event_for_action = function(agent_id, event_name, action_name, event_data, actions)
assert(agent_id ~= nil and agent_id ~= "", "agent id must be defined")
assert(event_name ~= nil and event_name ~= "", "event name must be defined")
assert(action_name ~= nil and action_name ~= "", "action name must be defined")
event_data = event_data or {}
actions = actions or {}
if action_name ~= "" then
local action_full_name = __config.ctx.name .. "." .. action_name
if glue.indexof(action_full_name, actions) == nil then
table.insert(actions, action_full_name)
end
end
smodule.push_event(agent_id, event_name, event_data, actions)
end
smodule.push_event = function(agent_id, event_name, event_data, actions)
assert(agent_id ~= nil and agent_id ~= "", "agent id must be defined")
assert(event_name ~= nil and event_name ~= "", "event name must be defined")