Cisco EEM 将 Syslog 消息传递给 TCL 脚本

网络工程 思科 系统日志 cisco-eem
2021-07-09 10:57:08

我使用的是带有IOS 15.1(3)T的 Cisco 1811 - 是的,它真的很旧,但这在这里可能无关紧要。

我有这个 TCL 脚本,可以将 HTTP POST 发送到目的地,我想将系统发出的任何 Syslog 消息传递到请求正文中。

<< my own http_get implementation here >>

namespace import ::cisco::eem::*
namespace import ::cisco::lib::*

set url "http://some.url.out.there:8000"
set mystdin [gets stdin]
set res [http_get $url -query $mystdin]

puts "POSTed to url"

我的事件管理器小程序如下所示:

event manager applet TRIGGER
    event syslog occurs 1 pattern "%.*"
    action 2.0 policy sendevent.tcl $_syslog_msg

现在这很好用,除了我没有进入任何东西$mystdin,所以我的请求正文是空的。

我如何将事件管理器传递$_syslog_msg给 TCL 脚本?也许有一种方法可以从脚本中查询“最后一个 Syslog 事件”,而无需从中读取stdin

1个回答

好的,所以

action policy POLICY_NAME $arg

不将参数传递给脚本 - 必须切换到

action cli command "tclsh flash:/script.tcl $arg"`

确实如此,但是...

EEM 操作无法从变量中捕获换行符以外的内容。我确实找到了出路 - 从$_syslog_msg(换行符是第一个字符)修剪换行符并分配给一个新变量。

这是端到端的解决方案:

CISCO-1811#sh run | s event
event manager directory user policy "flash:/"
event manager directory user library "flash:/"
event manager directory user repository tftp://1.1.1.3/
event manager applet TRIGGER_ON_SYSLOG
  event syslog occurs 1 pattern "%.*"
  action 1.0 string trimleft "$_syslog_msg"
  action 2.0 cli command "enable"
  action 2.1 cli command "tclsh flash:/sendevent.tcl \"$_string_result\""

$_string_result 是一个 EEM 内置变量,用于收集字符串 trimleft 的输出

http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/eem/command/eem-cr-book/eem-cr-a2.html

使用该action string trimleft命令从另一个字符串的左端修剪一个字符串。此命令string2从 的左端修剪由 指定的字符string1默认情况下,string2对应于空白。

下表显示了action string trimleft存储命令结果的内置变量

内置变量$_string_result

描述action string trimleft命令的结果存储在这个变量中。

以上实际上是不完整/误导/或 Cisco 不知道他们选择的语言是如何工作的: string trimleft没有第二个参数会修剪空格、制表符、换行符和 CR而不仅仅是空格(参见:http : //wiki.tcl.tk /10177)。

发送事件.tcl

#...
# my own http_get implementation here
# ...

# My actual event code

set url "http://some.http.destination:8000"

# Event log message is passed in as "$argv 0".
# That's the first item in $argv (which is a list)
set rawmsg [lindex $argv 0]

# Strip quotes from syslog message
set cleanmsg [string map { "\"" "" } $rawmsg]

# Get the time stamp at source
set timestamp [clock format [clock seconds] -format "%Y-%m-%dT%H:%M:%S"]

set json "{
    \"RouterTimestamp\": \"$timestamp\",
    \"Message\": \"$cleanmsg\"
}\n"

# This makes a POST request. Yes a POST.
# Don't know, ask the TCL developers what's with the name :)
if {[catch {http_get $url -query $json} token]} {
    puts "HTTP POST request failed: $token"
} else {
    # Everything is fine
    puts "POST successful."
}

结果

POST / HTTP/1.1
Accept: */*
Host: some.http.destination
User-Agent: Snobu Speshul TCL HTTP/1.1 Client library // build 21
Connection: close
Content-Length: 151
Content-Type: application/json

{
    "RouterTimestamp": "2017-02-02T10:09:49",
    "Message": "*Feb  2 10:09:49.307: %CLEAR-5-COUNTERS: Clear counter on all interfaces by console"
}

GitHub repo 在这里(代码完整):https : //github.com/snobu/cisco-syslog-over-http