node-red学习笔记——通过java远程调用linux shell初始化node-red并启动

柳轶
2023-12-01

大体思路:通过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>

 

 类似资料: