编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

JAVA实现Netconfig配置设备(java.net.inetsocketaddress)

wxchong 2024-07-05 01:43:29 开源技术 14 ℃ 0 评论

之前详细介绍了Neconfig网络配置协议的一些概念,没看过的小伙伴可以移步NetConfig协议详细介绍了解一下。Java作为应用最广泛的语言之一,今天主要讲Netconfig协议怎么在Java中使用。

JAVA实现Netconfig协议

1、进行Java开发之前,支持Netconfig协议的设备需要先开启SSH以及Netconfig使能。

2、Netconfig使用ssh协议进行远程连接,因此在java中需要使用ssh协议的jar包,本文使用是jsch-0.1.55.jar。Maven项目中可以如下配置:

<dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <vers之ion>0.1.55</version>
</dependency>

3、代码实现

直接上代码了,代码有点多,有兴趣的小伙伴可以粘贴到本地尝试一下。不过各个厂商的设备有些不同,我用的是东土的设备,关于组装xml命令的有些内容可以根据具体设备修改一下。

首先创建一个实体类Device当做客户端

package com.example.demo.netconfig;

import com.jcraft.jsch.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Getter
public class Device {

    private static final int DEFAULT_NETCONF_PORT = 830;
    private static final int DEFAULT_TIMEOUT = 3000;

    private String hostName;
    private int port;
    private int timeout;

    private String userName;
    private String password;

    private boolean keyBasedAuthentication;
    private String pemKeyFile;

    private boolean strictHostKeyChecking;
    private String hostKeysFileName;

    private JSch sshClient;
    private ChannelSubsystem sshChannel;
    private Session sshSession;

    private DocumentBuilder builder;
    private NetconfSession netconfSession;

    private List<String> netconfCapabilities;
    private String helloRpc;

    @Builder
    public Device(
            @NonNull String hostName,
            String password,
            Boolean keyBasedAuthentication,
            String pemKeyFile,
            Integer port,
            Integer timeout,
            @NonNull String userName,
            Boolean strictHostKeyChecking,
            String hostKeysFileName,
            List<String> netconfCapabilities
    ) throws IOException {
        this.hostName = hostName;
        this.port = (port != null) ? port : DEFAULT_NETCONF_PORT;
        this.timeout = (timeout != null) ? timeout : DEFAULT_TIMEOUT;

        this.userName = userName;
        this.password = password;

        if (this.password == null && pemKeyFile == null) {
            throw new IOException("Auth requires either setting the password or the pemKeyFile");
        }

        this.keyBasedAuthentication = (keyBasedAuthentication != null) ? keyBasedAuthentication : false;
        this.pemKeyFile = pemKeyFile;

        if (this.keyBasedAuthentication && pemKeyFile == null) {
            throw new IOException("key based authentication requires setting the pemKeyFile");
        }

        this.strictHostKeyChecking = (strictHostKeyChecking != null) ? strictHostKeyChecking : true;
        this.hostKeysFileName = hostKeysFileName;

        if (this.strictHostKeyChecking && hostKeysFileName == null) {
            throw new IOException("Strict Host Key checking requires setting the hostKeysFileName");
        }

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            builder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new IOException(String.format("Error creating XML Parser: %s", e.getMessage()));
        }

        this.netconfCapabilities = (netconfCapabilities != null) ? netconfCapabilities : getDefaultClientCapabilities();
        this.helloRpc = createHelloRPC(this.netconfCapabilities);

        this.sshClient = new JSch();
    }

   
    private List<String> getDefaultClientCapabilities() {
        List<String> defaultCap = new ArrayList<>();
        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0);
        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#candidate");
        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#confirmed-commit");
        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#validate");
        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#url?protocol=http,ftp,file");
        return defaultCap;
    }

  
    private String createHelloRPC(List<String> capabilities) {
        StringBuilder helloRPC = new StringBuilder();
        helloRPC.append("<hello xmlns=\"" + NetconfConstants.URN_XML_NS_NETCONF_BASE_1_0 + "\">\n");
        helloRPC.append("<capabilities>\n");
        for (Object o : capabilities) {
            String capability = (String) o;
            helloRPC
                    .append("<capability>")
                    .append(capability)
                    .append("</capability>\n");
        }
        helloRPC.append("</capabilities>\n");
        helloRPC.append("</hello>\n");
        helloRPC.append(NetconfConstants.DEVICE_PROMPT);
        return helloRPC.toString();
    }

  
    private NetconfSession createNetconfSession() throws IOException {
        if (!isConnected()) {
            sshClient = new JSch();

            try {
                if (strictHostKeyChecking) {
                    if (hostKeysFileName == null) {
                        throw new IOException("Cannot do strictHostKeyChecking if hostKeysFileName is null");
                    }
                    sshClient.setKnownHosts(hostKeysFileName);
                }
            } catch (JSchException e) {
                throw new IOException(String.format("Error loading known hosts file: %s", e.getMessage()));
            }
            sshClient.setHostKeyRepository(sshClient.getHostKeyRepository());
            //log.info("Connecting to host {} on port {}.", hostName, port);
            System.out.println("Connecting to host {} on port {}."+ hostName+ port);
            if (keyBasedAuthentication) {
                sshSession = loginWithPrivateKey(timeout);
                loadPrivateKey();
            } else {
                sshSession = loginWithUserPass(timeout);
            }
            try {
                sshSession.setTimeout(timeout);
            } catch (JSchException e) {
                throw new IOException(String.format("Error setting session timeout: %s", e.getMessage()));
            }
            if (sshSession.isConnected()) {
                //log.info("Connected to host {} - Timeout set to {} msecs.", hostName, sshSession.getTimeout());
                System.out.println("Connected to host {} - Timeout set to {} msecs."+hostName+ sshSession.getTimeout());
            } else {
                throw new IOException("Failed to connect to host. Unknown reason");
            }
        }
        try {
            sshChannel = (ChannelSubsystem) sshSession.openChannel("subsystem");
            sshChannel.setSubsystem("netconf");
            return new NetconfSession(sshChannel, timeout, helloRpc, builder);
        } catch (JSchException | IOException e) {
            throw new IOException("Failed to create Netconf session:" +
                    e.getMessage());
        }
    }

    private Session loginWithUserPass(int timeoutMilliSeconds) throws IOException {
        try {
            Session session = sshClient.getSession(userName, hostName, port);
            session.setConfig("userauth", "password");
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword(password);
            session.connect(timeoutMilliSeconds);
            return session;
        } catch (JSchException e) {
            throw new IOException(String.format("Error connecting to host: %s - Error: %s",
                    hostName, e.getMessage()));
        }
    }

    private Session loginWithPrivateKey(int timeoutMilliSeconds) throws IOException {
        try {
            Session session = sshClient.getSession(userName, hostName, port);
            session.setConfig("userauth", "publickey");
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect(timeoutMilliSeconds);
            return session;
        } catch (JSchException e) {
            throw new IOException(String.format("Error using key pair file: %s to connect to host: %s - Error: %s",
                    pemKeyFile, hostName, e.getMessage()));
        }
    }

    public void connect() throws IOException {
        if (hostName == null || userName == null || (password == null &&
                pemKeyFile == null)) {
            throw new IOException("Login parameters of Device can't be " +
                    "null.");
        }
        netconfSession = this.createNetconfSession();
    }

    private void loadPrivateKey() throws IOException {
        try {
            sshClient.addIdentity(pemKeyFile);
        } catch (JSchException e) {
            throw new IOException(String.format("Error parsing the pemKeyFile: %s", e.getMessage()));
        }
    }

    public String reboot() throws IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.reboot();
    }

    public boolean isConnected() {
        return (isChannelConnected() && isSessionConnected());
    }

    private boolean isChannelConnected() {
        if (sshChannel == null) {
            return false;
        }
        return sshChannel.isConnected();
    }

    private boolean isSessionConnected() {
        if (sshSession == null) {
            return false;
        }
        return sshSession.isConnected();
    }


    public void close() {
        if (!isConnected()) {
            return;
        }
        sshChannel.disconnect();
        sshSession.disconnect();
    }

    public String runShellCommand(String command) throws IOException {
        if (!isConnected()) {
            return "Could not find open connection.";
        }
        ChannelExec channel;
        try {
            channel = (ChannelExec) sshSession.openChannel("exec");
        } catch (JSchException e) {
            throw new IOException(String.format("Failed to open exec session: %s", e.getMessage()));
        }
        channel.setCommand(command);
        InputStream stdout;
        BufferedReader bufferReader;
        stdout = channel.getInputStream();

        bufferReader = new BufferedReader(new InputStreamReader(stdout, Charset.defaultCharset()));
        try {
            StringBuilder reply = new StringBuilder();
            while (true) {
                String line;
                try {
                    line = bufferReader.readLine();
                } catch (Exception e) {
                    throw new IOException(e.getMessage());
                }
                if (line == null || line.equals(""))
                    break;
                reply.append(line).append("\n");
            }
            return reply.toString();
        } finally {
            bufferReader.close();
        }
    }

    public BufferedReader runShellCommandRunning(String command)
            throws IOException {
        if (!isConnected()) {
            throw new IOException("Could not find open connection");
        }
        ChannelExec channel;
        try {
            channel = (ChannelExec) sshSession.openChannel("exec");
        } catch (JSchException e) {
            throw new IOException(String.format("Failed to open exec session: %s", e.getMessage()));
        }
        InputStream stdout = channel.getInputStream();
        return new BufferedReader(new InputStreamReader(stdout, Charset.defaultCharset()));
    }

    public XML executeRPC(String rpcContent) throws SAXException, IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.executeRPC(rpcContent);
    }


    public XML executeRPC(XML rpc) throws SAXException, IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.executeRPC(rpc);
    }

    public XML executeRPC(Document rpcDoc) throws SAXException, IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.executeRPC(rpcDoc);
    }

    public BufferedReader executeRPCRunning(String rpcContent) throws IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.executeRPCRunning(rpcContent);
    }


    public BufferedReader executeRPCRunning(XML rpc) throws IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.executeRPCRunning(rpc);
    }

    public BufferedReader executeRPCRunning(Document rpcDoc) throws IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.executeRPCRunning(rpcDoc);
    }

    public String getSessionId() {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot get session ID, you need " +
                    "to establish a connection first.");
        }
        return this.netconfSession.getSessionId();
    }

    public boolean hasError() throws SAXException, IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("No RPC executed yet, you need to" +
                    " establish a connection first.");
        }
        return this.netconfSession.hasError();
    }


    public boolean hasWarning() throws SAXException, IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("No RPC executed yet, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.hasWarning();
    }

    public boolean isOK() {
        if (netconfSession == null) {
            throw new IllegalStateException("No RPC executed yet, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.isOK();
    }

    public boolean lockConfig() throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.lockConfig();
    }

    public boolean unlockConfig() throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.unlockConfig();
    }

    public void loadXMLConfiguration(String configuration, String loadType)
            throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.loadXMLConfiguration(configuration, loadType);
    }

    public void loadTextConfiguration(String configuration, String loadType)
            throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.loadTextConfiguration(configuration, loadType);
    }

    public void loadSetConfiguration(String configuration) throws
            IOException,
            SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.loadSetConfiguration(configuration);
    }

    public void loadXMLFile(String configFile, String loadType)
            throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.loadXMLFile(configFile, loadType);
    }

    public void loadTextFile(String configFile, String loadType)
            throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.loadTextFile(configFile, loadType);
    }


    public void loadSetFile(String configFile) throws
            IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.loadSetFile(configFile);
    }

    public void commit() throws IOException, IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.commit();
    }

    public void commitConfirm(long seconds) throws IOException,
            SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.commitConfirm(seconds);
    }

    public void commitFull() throws IOException, IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.commitFull();
    }

    public void commitThisConfiguration(String configFile, String loadType)
            throws IOException, IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        this.netconfSession.commitThisConfiguration(configFile, loadType);
    }

    public XML getCandidateConfig(String configTree) throws SAXException,
            IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.getCandidateConfig(configTree);
    }

    public XML getRunningConfig(String configTree) throws SAXException,
            IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.getRunningConfig(configTree);
    }

    public XML getCandidateConfig() throws SAXException, IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.getCandidateConfig();
    }

    public XML getRunningConfig() throws SAXException, IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.getRunningConfig();
    }

    public boolean validate() throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.validate();
    }

    public String runCliCommand(String command) throws IOException, SAXException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.runCliCommand(command);
    }

    public BufferedReader runCliCommandRunning(String command) throws IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        return this.netconfSession.runCliCommandRunning(command);
    }

    public void openConfiguration(String mode) throws IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        netconfSession.openConfiguration(mode);
    }

    public void closeConfiguration() throws IOException {
        if (netconfSession == null) {
            throw new IllegalStateException("Cannot execute RPC, you need to " +
                    "establish a connection first.");
        }
        netconfSession.closeConfiguration();
    }

    public String getLastRPCReply() {
        return this.netconfSession.getLastRPCReply();
    }

}

创建一个CreateDevice类型表示创建连接。

package com.example.demo.netconfig;


import java.io.IOException;

public class CreateDevice {

    private static final String HOSTNAME = "192.168.2.75";
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "123";
    private static final String PEM_KEY_FILE_PATH = "/tmp/pemFile";


    public static Device createDevice() throws IOException {
        return Device.builder()
                .hostName(HOSTNAME)
                .userName(USERNAME)
                .password(PASSWORD)
                .strictHostKeyChecking(false)
                .build();
    }

    public static Device createDevice(String hostName, String userName, String passWord) throws IOException {
        return Device.builder()
                .hostName(hostName)
                .userName(userName)
                .password(passWord)
                .strictHostKeyChecking(false)
                .build();
    }

    public static Device createDeviceWithKeyAuth(String keyFile) throws IOException {
        return Device.builder()
                .hostName(HOSTNAME)
                .userName(USERNAME)
                .pemKeyFile(PEM_KEY_FILE_PATH)
                .strictHostKeyChecking(false)
                .build();
    }

    public static Device createDeviceWithKeyAuth(String hostName, String userName, String keyFile) throws IOException {
        return Device.builder()
                .hostName(hostName)
                .userName(userName)
                .pemKeyFile(keyFile)
                .strictHostKeyChecking(false)
                .build();
    }
}

创建一个NetconfSession类表示会话。


package com.example.demo.netconfig;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSchException;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class NetconfSession {

    private final Channel netconfChannel;
    private String serverCapability;

    private InputStream stdInStreamFromDevice;
    private OutputStream stdOutStreamToDevice;

    private String lastRpcReply;
    private final DocumentBuilder builder;
    private int messageId = 0;

    private static final String CANDIDATE_CONFIG = "candidate";
    private static final String EMPTY_CONFIGURATION_TAG = "<configuration></configuration>";
    private static final String RUNNING_CONFIG = "running";
    private static final String NETCONF_SYNTAX_ERROR_MSG_FROM_DEVICE = "netconf error: syntax error";

    NetconfSession(Channel netconfChannel, int timeout, String hello,
                   DocumentBuilder builder) throws IOException {

        stdInStreamFromDevice = netconfChannel.getInputStream();
        stdOutStreamToDevice = netconfChannel.getOutputStream();
        try {
            netconfChannel.connect(timeout);
        } catch (JSchException e) {
            throw new IOException("Failed to create Netconf session:" +
                    e.getMessage());
        }
        this.netconfChannel = netconfChannel;
        this.builder = builder;

        sendHello(hello);
    }

    private XML convertToXML(String xml) throws SAXException, IOException {
        if (xml.contains(NETCONF_SYNTAX_ERROR_MSG_FROM_DEVICE)) {
            throw new IOException(String.format("Netconf server detected an error: %s", xml));
        }
        Document doc = builder.parse(new InputSource(new StringReader(xml)));
        Element root = doc.getDocumentElement();
        return new XML(root);
    }

    private void sendHello(String hello) throws IOException {
        String reply = getRpcReply(hello);
        serverCapability = reply;
        lastRpcReply = reply;
    }

    @VisibleForTesting
    String getRpcReply(String rpc) throws IOException {
        
        BufferedReader bufferedReader = getRpcReplyRunning(rpc);

        StringBuilder rpcReply = new StringBuilder();
        while (!rpcReply.toString().contains(NetconfConstants.DEVICE_PROMPT)) {
            int line = bufferedReader.read();
            if (line == -1) {
                throw new IOException("Input Stream has been closed during reading.");
            }
            rpcReply.append((char) line);
        }

       
        String reply = rpcReply.toString().replace(NetconfConstants.DEVICE_PROMPT, "");
        System.out.println("Received Netconf RPC-Reply\n{}"+reply);
        return reply;
    }

    private BufferedReader getRpcReplyRunning(String rpc) throws IOException {
        messageId++;
        rpc = rpc.replace("<rpc>", "<rpc xmlns=\"" + NetconfConstants.URN_XML_NS_NETCONF_BASE_1_0 + "\" message-id=\"" + messageId + "\">").trim();
        if (!rpc.contains(NetconfConstants.XML_VERSION)) {
            rpc = NetconfConstants.XML_VERSION + rpc;
        }
        System.out.println("Sending Netconf RPC\n{}"+rpc);
        stdOutStreamToDevice.write(rpc.getBytes(Charsets.UTF_8));
        stdOutStreamToDevice.flush();
        return new BufferedReader(
                new InputStreamReader(stdInStreamFromDevice, Charsets.UTF_8));
    }

    public void loadXMLConfiguration(String configuration, String loadType) throws IOException, SAXException {
        validateLoadType(loadType);
        configuration = configuration.trim();
        if (!configuration.startsWith("<configuration")) {
            configuration = "<configuration>" + configuration
                    + "</configuration>";
        }
        String rpc = "<rpc>" +
                "<edit-config>" +
                "<target>" +
                "<" + CANDIDATE_CONFIG + "/>" +
                "</target>" +
                "<default-operation>" +
                loadType +
                "</default-operation>" +
                "<config>" +
                configuration +
                "</config>" +
                "</edit-config>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        if (hasError() || !isOK())
            throw new IOException("Load operation returned error.");
    }
    public void loadTextConfiguration(String configuration, String loadType) throws IOException, SAXException {
        String rpc = "<rpc>" +
                "<edit-config>" +
                "<target>" +
                "<" + CANDIDATE_CONFIG + "/>" +
                "</target>" +
                "<default-operation>" +
                loadType +
                "</default-operation>" +
                "<config-text>" +
                "<configuration-text>" +
                configuration +
                "</configuration-text>" +
                "</config-text>" +
                "</edit-config>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        if (hasError() || !isOK())
            throw new IOException("Load operation returned error");
    }

    private String getConfig(String configTree) throws IOException {

        String rpc = "<rpc>" +
                "<get-config>" +
                "<source>" +
                "<" + CANDIDATE_CONFIG + "/>" +
                "</source>" +
                "<filter type=\"subtree\">" +
                configTree +
                "</filter>" +
                "</get-config>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        return lastRpcReply;
    }

    private String getConfig(String target, String configTree)
            throws IOException {

        String rpc = "" + "<rpc>" +
                "<get-config>" +
                "<source>" +
                "<" + target + "/>" +
                "</source>" +
                "<filter type=\"subtree\">" +
                configTree +
                "</filter>" +
                "</get-config>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        return lastRpcReply;
    }

    public String getServerCapability() {
        return serverCapability;
    }


    public XML executeRPC(String rpcContent) throws SAXException, IOException {
        String rpc=fixupRpc(rpcContent);
        String rpcReply = getRpcReply(fixupRpc(rpcContent));
        lastRpcReply = rpcReply;
        return convertToXML(rpcReply);
    }


    public XML executeRPC(XML rpc) throws SAXException, IOException {
        return executeRPC(rpc.toString());
    }

    public XML executeRPC(Document rpcDoc) throws SAXException, IOException {
        Element root = rpcDoc.getDocumentElement();
        XML xml = new XML(root);
        return executeRPC(xml);
    }

    @VisibleForTesting
    static String fixupRpc(@NonNull String rpcContent) throws IllegalArgumentException {
        if (rpcContent == null) {
            throw new IllegalArgumentException("Null RPC");
        }
        rpcContent = rpcContent.trim();
        if (!rpcContent.startsWith("<rpc>") && !rpcContent.equals("<rpc/>")) {
            if (rpcContent.startsWith("<"))
                rpcContent = "<rpc>" + rpcContent + "</rpc>";
            else
                rpcContent = "<rpc>" + "<" + rpcContent + "/>" + "</rpc>";
        }
        return rpcContent + NetconfConstants.DEVICE_PROMPT;
    }

    public BufferedReader executeRPCRunning(String rpcContent) throws IOException {
        return getRpcReplyRunning(fixupRpc(rpcContent));
    }


    public BufferedReader executeRPCRunning(XML rpc) throws IOException {
        return executeRPCRunning(rpc.toString());
    }

    public BufferedReader executeRPCRunning(Document rpcDoc) throws IOException {
        Element root = rpcDoc.getDocumentElement();
        XML xml = new XML(root);
        return executeRPCRunning(xml);
    }

    public String getSessionId() {
        String[] split = serverCapability.split("<session-id>");
        if (split.length != 2)
            return null;
        String[] idSplit = split[1].split("</session-id>");
        if (idSplit.length != 2)
            return null;
        return idSplit[0];
    }

    public void close() throws IOException {
        String rpc = "<rpc>" +
                "<close-session/>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        netconfChannel.disconnect();
    }

    public boolean hasError() throws SAXException, IOException {
        if (lastRpcReply == null || !(lastRpcReply.contains("<rpc-error>")))
            return false;
        String errorSeverity = parseForErrors(lastRpcReply);
        return errorSeverity != null && errorSeverity.equals("error");
    }

    private String parseForErrors(String inputXmlReply) throws IOException, SAXException {
        XML xmlReply = convertToXML(lastRpcReply);
        List<String> tagList = new ArrayList<>();
        tagList.add("rpc-error");
        tagList.add("error-severity");
        return xmlReply.findValue(tagList);
    }

    public boolean hasWarning() throws SAXException, IOException {
        if (lastRpcReply == null || !(lastRpcReply.contains("<rpc-error>")))
            return false;
        String errorSeverity = parseForErrors(lastRpcReply);
        return errorSeverity != null && errorSeverity.equals("warning");
    }

    public boolean isOK() {
        return lastRpcReply != null && lastRpcReply.contains("<ok/>");
    }

    public boolean lockConfig() throws IOException, SAXException {
        String rpc = "<rpc>" +
                "<lock>" +
                "<target>" +
                "<candidate/>" +
                "</target>" +
                "</lock>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        return !hasError() && isOK();
    }

    public boolean unlockConfig() throws IOException, SAXException {
        String rpc = "<rpc>" +
                "<unlock>" +
                "<target>" +
                "<candidate/>" +
                "</target>" +
                "</unlock>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        return !hasError() && isOK();
    }

    public void loadSetConfiguration(String configuration) throws IOException, SAXException {
        String rpc = "<rpc>" +
                "<load-configuration action=\"set\">" +
                "<configuration-set>" +
                configuration +
                "</configuration-set>" +
                "</load-configuration>" +
                "</rpc>";
        lastRpcReply = getRpcReply(rpc);
        if (hasError() || !isOK())
            throw new IOException("Load operation returned error");
    }

    public void loadXMLFile(String configFile, String loadType) throws IOException, SAXException {
        validateLoadType(loadType);
        loadXMLConfiguration(readConfigFile(configFile), loadType);
    }

    private void validateLoadType(String loadType) throws IllegalArgumentException {
        if (loadType == null || (!loadType.equals("merge") &&
                !loadType.equals("replace")))
            throw new IllegalArgumentException("'loadType' argument must be " +
                    "merge|replace");
    }

    private String readConfigFile(String configFile) throws IOException {
        try {
            return new String(Files.readAllBytes(Paths.get(configFile)), Charset.defaultCharset().name());
        } catch (FileNotFoundException e) {
            throw new FileNotFoundException("The system cannot find the configuration file specified: " + configFile);
        }
    }

    public void loadTextFile(String configFile, String loadType) throws IOException, SAXException {
        validateLoadType(loadType);
        loadTextConfiguration(readConfigFile(configFile), loadType);
    }

    public void loadSetFile(String configFile) throws
            IOException, SAXException {
        loadSetConfiguration(readConfigFile(configFile));
    }

    public void commitThisConfiguration(String configFile, String loadType) throws IOException, SAXException {
        String configuration = readConfigFile(configFile);
        configuration = configuration.trim();
        if (this.lockConfig()) {
            if (configuration.startsWith("<")) {
                this.loadXMLConfiguration(configuration, loadType);
            } else if (configuration.startsWith("set")) {
                this.loadSetConfiguration(configuration);
            } else {
                this.loadTextConfiguration(configuration, loadType);
            }
            this.commit();
        } else {
            throw new IOException("Unclean lock operation. Cannot proceed " +
                    "further.");
        }
        this.unlockConfig();
    }

    public void commit() throws IOException, SAXException {
        String rpc = "<rpc>" +
                "<commit/>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        if (hasError() || !isOK())
            throw new IOException("Commit operation returned error.");
    }

    public void commitConfirm(long seconds) throws IOException, SAXException {
        String rpc = "<rpc>" +
                "<commit>" +
                "<confirmed/>" +
                "<confirm-timeout>" + seconds + "</confirm-timeout>" +
                "</commit>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        if (hasError() || !isOK())
            throw new IOException("Commit operation returned " +
                    "error.");
    }

    public void commitFull() throws IOException, IOException, SAXException {
        String rpc = "<rpc>" +
                "<commit-configuration>" +
                "<full/>" +
                "</commit-configuration>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        if (hasError() || !isOK())
            throw new IOException("Commit operation returned error.");
    }

    public XML getCandidateConfig(String configTree) throws SAXException,
            IOException {
        return convertToXML(getConfig(configTree));
    }

    public XML getRunningConfig(String configTree) throws SAXException,
            IOException {
        return convertToXML(getConfig(RUNNING_CONFIG, configTree));
    }

    public XML getCandidateConfig() throws SAXException, IOException {
        return convertToXML(getConfig(EMPTY_CONFIGURATION_TAG));
    }

    public XML getRunningConfig() throws SAXException, IOException {
        return convertToXML(getConfig(RUNNING_CONFIG, EMPTY_CONFIGURATION_TAG));
    }

    public boolean validate() throws IOException, SAXException {

        String rpc = "<rpc>" +
                "<validate>" +
                "<source>" +
                "<candidate/>" +
                "</source>" +
                "</validate>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
        return !hasError() && isOK();
    }

    public String reboot() throws IOException {
        String rpc = "<rpc>" +
                "<request-reboot/>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        return getRpcReply(rpc);
    }

    public String runCliCommand(String command) throws IOException, SAXException {

        String rpc = "<rpc>" +
                "<command format=\"text\">" +
                command +
                "</command>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        String rpcReply = getRpcReply(rpc);
        lastRpcReply = rpcReply;
        XML xmlReply = convertToXML(rpcReply);
        List<String> tags = new ArrayList<>();
        tags.add("output");
        String output = xmlReply.findValue(tags);
        if (output != null)
            return output;
        else
            return rpcReply;
    }

    public BufferedReader runCliCommandRunning(String command) throws
            IOException {

        String rpc = "<command format=\"text\">" +
                command +
                "</command>";
        return executeRPCRunning(rpc);
    }

    public void openConfiguration(String mode) throws IOException {

        StringBuilder rpc = new StringBuilder();
        rpc.append("<rpc>");
        rpc.append("<open-configuration>");
        if (mode.startsWith("<"))
            rpc.append(mode);
        else
            rpc.append("<").append(mode).append("/>");
        rpc.append("</open-configuration>");
        rpc.append("</rpc>");
        rpc.append(NetconfConstants.DEVICE_PROMPT);
        lastRpcReply = getRpcReply(rpc.toString());
    }

    public void closeConfiguration() throws IOException {
        String rpc = "<rpc>" +
                "<close-configuration/>" +
                "</rpc>" +
                NetconfConstants.DEVICE_PROMPT;
        lastRpcReply = getRpcReply(rpc);
    }

    public String getLastRPCReply() {
        return this.lastRpcReply;
    }

}

创建一个NetconfConstans类表示netconfig命令需要用到的一些公共部分。

package com.example.demo.netconfig;

public class NetconfConstants {

    public static final String DEVICE_PROMPT = "]]>]]>";

    public static final String XML_VERSION = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

    public static final String URN_XML_NS_NETCONF_BASE_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0";

    public static final String URN_IETF_PARAMS_NETCONF_BASE_1_0 = "urn:ietf:params:netconf:base:1.0";

}

创建一个XML类接收设备返回的XML消息。

package com.example.demo.netconfig;

import com.google.common.base.Preconditions;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class XML {

    private final Element activeElement;
    private final Document ownerDoc;

    protected XML(Element active) {
        this.activeElement = active;
        ownerDoc = active.getOwnerDocument();
    }

    private String trim(String str) {
        String st = str.trim();
        if (st.startsWith("\n"))
            st = st.substring(st.indexOf("\n") +1);
        if (st.endsWith("\n")) {
            st = st.substring(0,st.lastIndexOf("\n"));
        }
        return st;
    }

   
    public Document getOwnerDocument() {
        return this.ownerDoc;
    }

  
    public XML append(String element) {
        Element newElement = ownerDoc.createElement(element);
        activeElement.appendChild(newElement);
        return new XML(newElement);
    }

 
    public XML append(String element, String text) {
        Element newElement = ownerDoc.createElement(element);
        Node textNode = ownerDoc.createTextNode(text);
        newElement.appendChild(textNode);
        activeElement.appendChild(newElement);
        return new XML(newElement);
    }

  
    public void append(String element, String[] text) {
        for (String s : text) {
            Element newElement = ownerDoc.createElement(element);
            Node textNode = ownerDoc.createTextNode(s);
            newElement.appendChild(textNode);
            activeElement.appendChild(newElement);
        }
    }

  
    public void append(Map<String, String> map) {
        List<String> keyList = new ArrayList<>(map.keySet());
        for (Object element : keyList) {
            String elementName = (String) element;
            String text = map.get(element);
            Element newElement = ownerDoc.createElement(elementName);
            Node textNode = ownerDoc.createTextNode(text);
            newElement.appendChild(textNode);
            activeElement.appendChild(newElement);
        }
    }

  
    public XML append(String element, Map<String, String> map) {
        Element newElement = ownerDoc.createElement(element);
        activeElement.appendChild(newElement);
        XML newXML = new XML(newElement);
        newXML.append(map);
        return newXML;
    }

    public void addSibling(String element) {
        Element newElement = ownerDoc.createElement(element);
        Node parentNode = activeElement.getParentNode();
        parentNode.appendChild(newElement);
    }

    public void addSibling(String element, String text) {
        Element newElement = ownerDoc.createElement(element);
        Node textNode = ownerDoc.createTextNode(text);
        newElement.appendChild(textNode);
        Node parentNode = activeElement.getParentNode();
        parentNode.appendChild(newElement);
    }

    public void addSiblings(String element, String[] text) {
        Node parentNode = activeElement.getParentNode();
        for (String s : text) {
            Element newElement = ownerDoc.createElement(element);
            Node textNode = ownerDoc.createTextNode(s);
            newElement.appendChild(textNode);
            parentNode.appendChild(newElement);
        }
    }

    public void addSiblings(Map<String, String> map) {
        List<String> keyList = new ArrayList<>(map.keySet());
        activeElement.getParentNode();
        for (Object element : keyList) {
            String elementName = (String) element;
            String text = map.get(element);
            Element newElement = ownerDoc.createElement(elementName);
            Node textNode = ownerDoc.createTextNode(text);
            newElement.appendChild(textNode);
            activeElement.appendChild(newElement);        }
    }

    public XML addPath(String path) {
        String[] elements = path.split("/");
        Preconditions.checkArgument(elements.length >= 1);
        Element newElement = null;
        for (String element : elements) {
            newElement = ownerDoc.createElement(element);
            activeElement.appendChild(newElement);
        }
        return new XML(Objects.requireNonNull(newElement));
    }

    public void setAttribute(String name, String value) {
        activeElement.setAttribute(name, value);
    }

    public void setText(String text) {
        Node firstChild = activeElement.getFirstChild();
        if (firstChild == null || firstChild.getNodeType() != Node.TEXT_NODE) {
            Node textNode = ownerDoc.createTextNode(text);
            activeElement.appendChild(textNode);
        } else {
            firstChild.setNodeValue(text);
        }
    }

    public void junosDelete() {
        activeElement.setAttribute("delete", "delete");
    }

    public void junosActivate() {
        activeElement.setAttribute("active", "active");
    }

    public void junosDeactivate() {
        activeElement.setAttribute("inactive", "inactive");
    }

    public void junosRename(String toBeRenamed, String newName) {
        activeElement.setAttribute("rename", toBeRenamed);
        activeElement.setAttribute("name", newName);
    }

    public void junosInsert(String before, String name) {
        activeElement.setAttribute("insert", before);
        activeElement.setAttribute("name", name);
    }

    public String findValue(List<String> list) {
        Element nextElement = ownerDoc.getDocumentElement();
        boolean nextElementFound;
        for (int k=0; k<list.size(); k++) {
            nextElementFound = false;
            String nextElementName = list.get(k);
            if (!nextElementName.contains("~")){
                try {
                    NodeList nextElementList = nextElement.
                            getElementsByTagName(nextElementName);
                    String n2nString = null;
                    if (k<list.size()-1)
                        n2nString = list.get(k+1);
                    if (n2nString != null && n2nString.contains("~")) {
                        String n2nText = n2nString.substring(n2nString.
                                indexOf("~") + 1);
                        String n2nElementName = n2nString.substring(0,
                                n2nString.indexOf("~"));
                        for (int i=0; i<nextElementList.getLength(); i++) {
                            nextElement = (Element)nextElementList.item(i);
                            Element n2nElement = (Element)nextElement.
                                    getElementsByTagName(n2nElementName).item(0);
                            String text = n2nElement.getFirstChild().
                                    getNodeValue();
                            text = trim(text);
                            if (text != null && text.equals(n2nText)) {
                                nextElementFound = true;
                                break;
                            }
                        }
                        if (!nextElementFound)
                            return null;
                    } else {
                        nextElement = (Element)nextElementList.item(0);
                    }
                } catch(NullPointerException e) {
                    return null;
                }
            }        }
        if (nextElement == null) {
            return null;
        }
        String value = nextElement.getFirstChild().getNodeValue();
        if (value == null) {
            return null;
        }
        return trim(value);
    }

    public List<Node> findNodes(List<String> list) {
        Element nextElement = ownerDoc.getDocumentElement();
        boolean nextElementFound;
        List<Node> finalList = new ArrayList<>();
        for (int k=0; k<list.size(); k++) {
            nextElementFound = false;
            String nextElementName = list.get(k);
            if (!nextElementName.contains("~")) {
                try {
                    NodeList nextElementList = nextElement.
                            getElementsByTagName(nextElementName);
                    String n2nString = null;
                    if (k<list.size()-1)
                        n2nString = list.get(k+1);
                    if (n2nString != null && n2nString.contains("~")) {
                        String n2nText = n2nString.substring(n2nString.
                                indexOf("~") + 1);
                        String n2nElementName = n2nString.substring(0,
                                n2nString.indexOf("~"));
                        for (int i=0; i<nextElementList.getLength(); i++) {
                            nextElement = (Element)nextElementList.item(i);
                            Element n2nElement = (Element)nextElement.
                                    getElementsByTagName(n2nElementName).item(0);
                            String text = n2nElement.getFirstChild().
                                    getNodeValue();
                            text = trim(text);
                            if (text != null && text.equals(n2nText)) {
                                nextElementFound = true;
                                break;
                            }
                        }
                        if (!nextElementFound)
                            return null;
                    } else {
                        nextElement = (Element)nextElementList.item(0);
                    }
                } catch(NullPointerException e) {
                    return null;
                }
            }
        }
        if (nextElement == null) {
            return null;
        }
        String nodeName = nextElement.getNodeName();
        String listLastEntry = list.get(list.size()-1);
        if (listLastEntry.contains("~")) {
            finalList.add(nextElement);
            return finalList;

        } else {
            Element parent = (Element)nextElement.getParentNode();
            NodeList nodeList = parent.getElementsByTagName(nodeName);
            for (int i=0; i<nodeList.getLength(); i++) {
                finalList.add(nodeList.item(i));
            }
            return finalList;

        }
    }

    public String toString() {
        String str;
        try {
            TransformerFactory transFactory = TransformerFactory.newInstance();
            Transformer transformer = transFactory.newTransformer();
            StringWriter buffer = new StringWriter();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty
                    ("{http://xml.apache.org/xslt}indent-amount", "4");
            Element root = ownerDoc.getDocumentElement();
            transformer.transform(new DOMSource(root), new StreamResult(buffer));
            str = buffer.toString();
        } catch (TransformerException ex) {
            str = "Could not transform: Transformer exception";
        }
        return str;
    }
}

最后创建一个NetconfigUtil类,进行连接并发送命令测试。

package com.example.demo.netconfig;

import cn.hutool.core.util.StrUtil;
import org.dom4j.DocumentException;
import org.xml.sax.SAXException;

import java.io.IOException;

public class NetconfUtils {

    public static String getDevXML(String ip, String userName, String password, String msg) throws IOException, SAXException,RuntimeException{
        if (StrUtil.isEmpty(ip) || StrUtil.isEmpty(userName) || StrUtil.isEmpty(password) || StrUtil.isEmpty(msg))
            throw new RuntimeException("    |--用户名 或 密码 或 IP 或下发的数据为空 ");

        String rpc_reply = null;


        try {
            Device device = CreateDevice.createDevice(ip, userName, password);
            device.connect();

            rpc_reply = device.executeRPC(msg);
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
//        device.close();
        return rpc_reply;
    }

    public static void main(String args[]) throws IOException, SAXException, DocumentException {
        String message = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<get>\n" +
                "    <filter>\n" +
                "        <kylandDev xmlns=\"urn:kyland:parpms:xml:ns:yang:kyland-dev\"></kylandDev>\n" +
                "    </filter>\n" +
                "</get>";
        String msg = "\t<get>\n" +
                "\n" +
                "\t\t<filter>\n" +
                "\t\t\t<kylandLldp xmlns=\"urn:kyland:parpms:xml:ns:yang:kyland-lldp\"></kylandLldp>\n" +
                "\t\t</filter>\n" +
                "</get>";
        String devXML = NetconfUtils.getDevXML("192.168.100.15", "admin", "123", message);
        System.out.println("****************");
        System.out.println(devXML);

    }
}

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表