大体思路:通过java远程调用linux shell,创建node-red的flows_xxx.json文件,然后启动node-red并指定json文件。
(在node-red操作界面添加的节点都会保存到相应json文件中,windows默认保存位置:C:\Users\LENOVO\.node-red,linux:~/.node-red。保存位置可以在启动服务的时候去指定
Usage: node-red [-v] [-?] [--settings settings.js] [--userDir DIR] [flows.json]
Options:
-s, --settings FILE use specified settings file
-u, --userDir DIR use specified user directory
-v enable verbose output
-?, --help show usage
建议看下官方文档 https://nodered.org/docs/getting-started/running,推荐使用谷歌浏览器直接右键翻译)
先放shell脚本:
#!/bin/bash
PRODUCT_ID=$1
FILE_NAME="flows_"$PRODUCT_ID".json"
PORT=$2
#create new flows_xxx.json
cd /usr/soft/node-red-flows
touch $FILE_NAME
# startup node-red server
nohup node-red -p $PORT $FILE_NAME > myout.file 2>&1 &
# return pid
printf $!"end"
需要传递两个参数,产品id和端口号(当初的想法是一个产品一个端口号,启动一个node-red。其他方案参考:多个产品只部署且公用一个node-red服务,点开不同产品去查询加载到ui界面上,但是还有一个问题,如果这样的话,没有点开的产品所在的node-red服务也必须是启动的,所以你得会去改源码,有兴趣的可以去研究下)
注:脚本最后返回node-red服务占用的PID号,为以后停止服务杀进程做准备
nohup 命令 > 打印输出文件 2>&1 & 将命令放到后台去执行,并把标准和错误输出到指定文件,不占用控制台(或者说关掉控制台后让程序继续运行)
参考:https://blog.csdn.net/zxh2075/article/details/52932885
PID后面那个end,因为java请求后接收到的信息除了PID,还有好长一段方格,所以就和java端约定了一下,以end为结束标志去截取
下面贴上java端代码:
import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import com.venus.iot.commons.constants.PromptConstant;
import com.venus.iot.commons.constants.ServiceAddress;
import com.venus.iot.commons.model.ResultDTO;
import com.venus.iot.commons.shell.ShellKit;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
/**
* 远程调用shell
*
* @author hanpengcheng
* @date 2018/7/12 13:53
*/
public class SSH2Kit implements ShellKit {
private Connection conn;
private String ipAddr;
private String charset = Charset.defaultCharset().toString();
private String userName;
private String password;
private static final int TIME_OUT = 1000 * 5 * 60;
/**
* 构造方法
*
* @param ipAddr
* @param userName
* @param password
* @param charset
*/
public SSH2Kit(String ipAddr, String userName, String password,
String charset) {
this.ipAddr = ipAddr;
this.userName = userName;
this.password = password;
if (charset != null) {
this.charset = charset;
}
}
/**
* 执行shell
*
* @param cmds
* @return
*/
@Override
public ResultDTO runShell(String cmds) {
Session session = null;
InputStream stdOut = null;
InputStream stdErr = null;
String outStr = "";
String outErr = "";
int ret = -1;
try {
if (login()) {
// Open a new {@link Session} on this connection
session = conn.openSession();
// Execute a command on the remote machine.
session.execCommand(cmds);
stdOut = new StreamGobbler(session.getStdout());
outStr = processStream(stdOut, charset);
// stdErr = new StreamGobbler(session.getStderr());
// outErr = processStream(stdErr, charset);
// GobblerThread gtOut = new GobblerThread(session.getStdout(),"STD_OUT");
// GobblerThread gtErr = new GobblerThread(session.getStderr(),"STD_ERR");
// gtOut.start();
// gtErr.start();
// 等待,除非1.连接关闭;2.输出数据传送完毕;3.进程状态为退出;4.超时
//ChannelCondition.CLOSED | ChannelCondition.EOF |
//ChannelCondition.EXIT_STATUS
session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
// System.out.println("outStr=" + outStr);
// System.out.println("outErr=" + outErr);
// ret = session.getExitStatus();
if(StringUtils.isEmpty(outStr)){
return ResultDTO.getFailure("未获取到node-red服务进程的PID");
}
return ResultDTO.getSuccess(outStr);
} else {
return ResultDTO.getFailure("登录远程机器失败" + ipAddr);
}
} catch (IOException e) {
e.printStackTrace();
return ResultDTO.getFailure(PromptConstant.OPERATION_FAILURE);
} catch (Exception e) {
e.printStackTrace();
return ResultDTO.getFailure(PromptConstant.OPERATION_FAILURE);
} finally {
try {
stdOut.close();
// stdErr.close();
session.close();
if (conn != null) {
conn.close();
}
} catch (IOException e) {
e.printStackTrace();
return ResultDTO.getFailure(PromptConstant.OPERATION_FAILURE);
}
}
}
/**
* 远程登录linux的主机
*
* @return
* @throws IOException
*/
public boolean login() throws IOException {
conn = new Connection(ipAddr);
conn.connect(); // 连接
return conn.authenticateWithPassword(userName, password); // 认证
}
/**
* 解析脚本执行返回的结果集
*
* @param in
* @param charset
* @return
*/
private String processStream(InputStream in, String charset) {
byte[] buf = new byte[1024];
StringBuffer sb = new StringBuffer();
String tmpStr;
try {
while (in.read(buf) != -1) {
tmpStr=new String(buf, charset);
String [] strs = tmpStr.split("[end]");
String tmp=strs[0];
if(StringUtils.isNotEmpty(tmp)){
sb.append(tmp);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
/**
* @param args
*/
// public static void main(String[] args) {
//
// SSH2Kit kit = new SSH2Kit(NodeRedConfig.getServerIP(), ServiceAddress.SERVER_LOGIN_USER_NAME,
// ServiceAddress.SERVICE_LOGIN_PASSWORD, "utf-8");
// Object result = kit.runShell(ServiceAddress.NODE_RED_CREATE_FLOWS_FILE_SHELL+" abc 10000");
// System.out.print(result);
//
// }
补个pom:
<dependency>
<groupId>org.jvnet.hudson</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>build210-hudson-1</version>
</dependency>