使用ExecuteScript,Groovy和Sshoogr在NiFi中执行远程命令

文章介绍了在Apache NiFi中执行远程命令的方法。可通过ExecuteProcess等处理器调用“ssh”命令,也可用ExecuteScript结合Groovy和Sshoogr库。文中说明了Sshoogr的安装、脚本编写、配置参数设置等,还给出完整脚本及配置示例,展示了执行远程命令的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Apache NiFi中已经有一些处理器用于执行命令,例如ExecuteProcess和ExecuteStreamCommand。
这些允许通过使用各种参数(例如建立SSH会话时要执行的远程命令)调用操作系统的“ssh”命令来执行远程脚本。
通常这是通过编写带有许多ssh命令的bash脚本(或者在末尾使用一长串远程命令的单个ssh命令)来完成的。

作为一种不同的方法,您可以使用ExecuteScript或InvokeScriptedProcessor以及第三方库来使用SSH执行远程命令。
对于这篇文章,我将使用Groovy作为脚本语言和Sshoogr,这是一个非常方便的Groovy SSH DSL。

Sshoogr可以通过SDK Manager安装或下载(例如从Maven Central)。
关键是将所有库(Sshoogr本身及其依赖项)放在某个目录中。
然后指向ExecuteScript的Module Directory属性中的目录,这些JAR将可用于Groovy脚本。

为了使这个例子相当灵活,我选择了一些约定。
首先,要执行的命令应该在传入流文件的各行上。
接下来,配置参数(例如主机名,用户名,密码和端口)将作为动态属性添加到ExecuteScript。
请注意,在这种情况下,password属性不敏感;
如果需要,请使用InvokeScriptedProcessor并显式添加属性(将密码指定为敏感密码)。

为了使Sshoogr工作(至少在本例中),预计远程节点的RSA密钥位于NiFi用户的〜/ .ssh / known_hosts文件中。
由于操作系统和其他差异,有时SSH连接会因严格的主机密钥检查而失败,因此在脚本中我们将在Sshoogr中禁用它。

现在到脚本。
我们从需要输入流文件的标准代码开始,然后使用session.read()将每行放入名为命令的列表中:

def flowFile = session.get()
if(!flowFile) return

def commands = []
// Read in one command per line
session.read(flowFile, {inputStream ->
    inputStream.eachLine { line -> commands << line  }
} as InputStreamCallback)

然后我们禁用严格的主机密钥检查:

options.trustUnknownHosts = true

然后我们使用Sshoogr DSL执行流文件中的命令:

def result = null
remoteSession {

   host = sshHostname.value
   username = sshUsername.value
   password = sshPassword.value
   port = Integer.parseInt(sshPort.value)
        
   result = exec(showOutput: true, failOnError: false, command: commands.join('\n'))
}

这里我们使用前面提到的ExecuteScript动态属性(sshHostname,sshUsername,sshPassword,sshPort)。
在帖子的后面,下面的屏幕截图显示了它们在添加到ExecuteScript配置后。

exec()方法是Sshoogr的强者。
在这种情况下,我们需要输出命令(放入传出的流文件)。
此外,我将“failOnError”设置为false,因此将尝试所有命令,但您可能希望这是真的,这样如果命令失败,将不会尝试以下任何命令。
此示例中的最后一个参数是“command”。
如果你不使用exec()的“命名参数”(又名Map)版本而只想执行命令列表(例如没有设置“showOutput”),那么exec()将采用一个Collection:

exec(commands)

在我们的例子中,exec()方法会将“command”参数转换为字符串,因此我们需要将其转换为逐行字符串,而不是仅仅传入List“命令”,所以我们
使用join(’\ n’)。

脚本的下一部分是覆盖传入的流文件,或者如果我们可以创建一个新的原始文件作为父文件。
如果使用ExecuteScript并创建新的流文件,请务必删除原始文件。
如果使用InvokeScriptedProcessor,您可以定义“原始”关系并将传入流文件路由到该关系。

flowFile = session.write(flowFile, { outputStream ->
    result?.output?.eachLine { line ->
       outputStream.write(line.bytes)
       outputStream.write('\n'.bytes)
    }
} as OutputStreamCallback)

最后,使用result.exitStatus,我们确定是否将流文件路由到成功或失败:

session.transfer(flowFile, result?.exitStatus ? REL_FAILURE : REL_SUCCESS)

此示例的完整脚本如下:

import static com.aestasit.infrastructure.ssh.DefaultSsh.*

def flowFile = session.get()
if(!flowFile) return

def commands = []
// Read in one command per line
session.read(flowFile, {inputStream ->
    inputStream.eachLine { line -> commands << line  }
} as InputStreamCallback)

options.trustUnknownHosts = true
def result = null
remoteSession {

   host = sshHostname.value
   username = sshUsername.value
   password = sshPassword.value
   port = Integer.parseInt(sshPort.value)
        
   result = exec(showOutput: true, failOnError: false, command: commands.join('\n'))
}

flowFile = session.write(flowFile, { outputStream ->
    result?.output?.eachLine { line ->
       outputStream.write(line.bytes)
       outputStream.write('\n'.bytes)
    }
} as OutputStreamCallback)

session.transfer(flowFile, result?.exitStatus ? REL_FAILURE : REL_SUCCESS)

现在转到ExecuteScript配置:
在这里插入图片描述
在这里,我连接到我的Hortonworks数据平台(HDP)Sandbox以运行Hadoop命令等,显示默认设置,您可以看到我已将脚本粘贴到Script Body中,而我的Module Directory指向我的Sshoogr下载文件夹。
我将此添加到生成流文件的简单流中,使用命令填充它,远程运行它们,然后记录会话返回的输出:
在这里插入图片描述
在本例中,我运行了以下两个命令:

hadoop fs -ls /user
echo "Hello World!" > here_i_am.txt

在日志中(在包含有效负载的LogAttribute运行之后),我看到以下内容:
在这里插入图片描述
在沙盒上,我看到文件已经创建了预期的内容:
在这里插入图片描述
如您所见,这篇文章描述了如何使用带Groovy和Sshoogr的ExecuteScript来执行来自流文件的远程命令。
我创建了模板的Gist,但它是使用Apache NiFi 1.0的beta版本创建的,因此它可能无法加载到早期版本(0.x)。
然而所有的成分都在这篇文章中,所以应该很容易创建自己的流程,请告诉我如何/如果它适合你:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值