From 5420d0e3a092fa267ef3a594a392f1a7ca10b464 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 6 Oct 2017 13:32:51 -0700 Subject: [PATCH 1/2] WIP on long-lived program outputs. --- falco.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/falco.yaml b/falco.yaml index 0d699d6133a..1000d4fcfff 100644 --- a/falco.yaml +++ b/falco.yaml @@ -66,6 +66,12 @@ stdout_output: # - logging (alternate method than syslog): # program: logger -t falco-test +# If keep_alive is set to true, the program will be started once and +# continuously written to, with each output message on its own +# line. If keep_alive is set to false, the program will be re-spawned +# for each output message. + program_output: enabled: false + keep_alive: false program: mail -s "Falco Notification" someone@example.com From 1635d08df0d896f908187153850ea7783dfd8ee3 Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 6 Oct 2017 14:57:41 -0700 Subject: [PATCH 2/2] Allow outputs to keep file/program open Add the ability to keep file/program outputs open (i.e. writing to the same open file/program for multiple notifications). A new option to the file/program output "keep_alive", if true, keeps the file/program pipe open across events. This makes the need for unbuffered output aka https://github.com/draios/falco/issues/211 more pressing. Will add that next. --- falco.yaml | 7 +++++++ userspace/falco/configuration.cpp | 12 +++++++++-- userspace/falco/lua/output.lua | 34 ++++++++++++++++++++++++++----- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/falco.yaml b/falco.yaml index 1000d4fcfff..64220494529 100644 --- a/falco.yaml +++ b/falco.yaml @@ -53,8 +53,13 @@ outputs: syslog_output: enabled: true +# If keep_alive is set to true, the file will be opened once and +# continuously written to, with each output message on its own +# line. If keep_alive is set to false, the file will be re-opened +# for each output message. file_output: enabled: false + keep_alive: false filename: ./events.txt stdout_output: @@ -65,6 +70,8 @@ stdout_output: # program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/XXX" # - logging (alternate method than syslog): # program: logger -t falco-test +# - send over a network connection: +# program: nc host.example.com 80 # If keep_alive is set to true, the program will be started once and # continuously written to, with each output message on its own diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 7cfe4a57e99..6d266311599 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -71,13 +71,17 @@ void falco_configuration::init(string conf_filename, list &cmdline_optio file_output.name = "file"; if (m_config->get_scalar("file_output", "enabled", false)) { - string filename; + string filename, keep_alive; filename = m_config->get_scalar("file_output", "filename", ""); if (filename == string("")) { throw invalid_argument("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block"); } file_output.options["filename"] = filename; + + keep_alive = m_config->get_scalar("file_output", "keep_alive", ""); + file_output.options["keep_alive"] = keep_alive; + m_outputs.push_back(file_output); } @@ -99,13 +103,17 @@ void falco_configuration::init(string conf_filename, list &cmdline_optio program_output.name = "program"; if (m_config->get_scalar("program_output", "enabled", false)) { - string program; + string program, keep_alive; program = m_config->get_scalar("program_output", "program", ""); if (program == string("")) { throw sinsp_exception("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block"); } program_output.options["program"] = program; + + keep_alive = m_config->get_scalar("program_output", "keep_alive", ""); + program_output.options["keep_alive"] = keep_alive; + m_outputs.push_back(program_output); } diff --git a/userspace/falco/lua/output.lua b/userspace/falco/lua/output.lua index f4d571f3168..b0f5145add7 100644 --- a/userspace/falco/lua/output.lua +++ b/userspace/falco/lua/output.lua @@ -29,7 +29,7 @@ function mod.file_validate(options) error("File output needs to be configured with a valid filename") end - file, err = io.open(options.filename, "a+") + local file, err = io.open(options.filename, "a+") if file == nil then error("Error with file output: "..err) end @@ -38,9 +38,21 @@ function mod.file_validate(options) end function mod.file(priority, priority_num, msg, options) - file = io.open(options.filename, "a+") + if options.keep_alive == "true" then + if file == nil then + file = io.open(options.filename, "a+") + end + else + file = io.open(options.filename, "a+") + end + file:write(msg, "\n") - file:close() + + if options.keep_alive == nil or + options.keep_alive ~= "true" then + file:close() + file = nil + end end function mod.syslog(priority, priority_num, msg, options) @@ -52,10 +64,22 @@ function mod.program(priority, priority_num, msg, options) -- successfully. However, the luajit we're using returns true even -- when the shell can't run the program. - file = io.popen(options.program, "w") + -- Note: options are all strings + if options.keep_alive == "true" then + if file == nil then + file = io.popen(options.program, "w") + end + else + file = io.popen(options.program, "w") + end file:write(msg, "\n") - file:close() + + if options.keep_alive == nil or + options.keep_alive ~= "true" then + file:close() + file = nil + end end function output_event(event, rule, priority, priority_num, format)