blob: 17f6187215a057ae561a648a177b7ebf1579710a [file] [log] [blame]
andreaeb70a942015-10-16 21:34:46 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
andreaeb70a942015-10-16 21:34:46 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.netconf.ctl;
18
19import ch.ethz.ssh2.Connection;
20import ch.ethz.ssh2.Session;
21import com.google.common.base.Preconditions;
22import org.onosproject.netconf.NetconfDeviceInfo;
Andrea Campanella101417d2015-12-11 17:58:07 -080023import org.onosproject.netconf.NetconfDeviceOutputEvent;
24import org.onosproject.netconf.NetconfDeviceOutputEventListener;
25import org.onosproject.netconf.NetconfException;
andreaeb70a942015-10-16 21:34:46 -070026import org.onosproject.netconf.NetconfSession;
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
andreaeb70a942015-10-16 21:34:46 -070030import java.io.IOException;
Andreas Papazoisd4712e22016-02-10 15:59:55 +020031import java.util.ArrayList;
Andrea Campanella1cd641b2015-12-07 17:28:34 -080032import java.util.Collections;
Andrea Campanella101417d2015-12-11 17:58:07 -080033import java.util.HashMap;
andreaeb70a942015-10-16 21:34:46 -070034import java.util.List;
Andrea Campanella101417d2015-12-11 17:58:07 -080035import java.util.Map;
Andreas Papazoisd4712e22016-02-10 15:59:55 +020036import java.util.Optional;
Andrea Campanella101417d2015-12-11 17:58:07 -080037import java.util.concurrent.CompletableFuture;
Andrea Campanellab029b9e2016-01-29 11:05:36 -080038import java.util.concurrent.ExecutionException;
39import java.util.concurrent.TimeUnit;
40import java.util.concurrent.TimeoutException;
Andrea Campanella101417d2015-12-11 17:58:07 -080041import java.util.concurrent.atomic.AtomicInteger;
42
andreaeb70a942015-10-16 21:34:46 -070043
44/**
45 * Implementation of a NETCONF session to talk to a device.
46 */
47public class NetconfSessionImpl implements NetconfSession {
48
Andrea Campanella101417d2015-12-11 17:58:07 -080049 private static final Logger log = LoggerFactory
andreaeb70a942015-10-16 21:34:46 -070050 .getLogger(NetconfSessionImpl.class);
Andrea Campanella101417d2015-12-11 17:58:07 -080051
52
andreaeb70a942015-10-16 21:34:46 -070053 private static final int CONNECTION_TIMEOUT = 0;
Andrea Campanella101417d2015-12-11 17:58:07 -080054 private static final String ENDPATTERN = "]]>]]>";
Andrea Campanella101417d2015-12-11 17:58:07 -080055 private static final String MESSAGE_ID_STRING = "message-id";
Andrea Campanella1311ea02016-03-04 17:51:25 -080056 private static final String HELLO = "<hello";
Andrea Campanella101417d2015-12-11 17:58:07 -080057 private static final String NEW_LINE = "\n";
Andrea Campanellab029b9e2016-01-29 11:05:36 -080058 private static final String END_OF_RPC_OPEN_TAG = "\">";
59 private static final String EQUAL = "=";
60 private static final String NUMBER_BETWEEN_QUOTES_MATCHER = "\"+([0-9]+)+\"";
61 private static final String XML_HEADER =
62 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
andreaeb70a942015-10-16 21:34:46 -070063
Andrea Campanellab029b9e2016-01-29 11:05:36 -080064 private final AtomicInteger messageIdInteger = new AtomicInteger(0);
andreaeb70a942015-10-16 21:34:46 -070065 private Connection netconfConnection;
66 private NetconfDeviceInfo deviceInfo;
67 private Session sshSession;
68 private boolean connectionActive;
andreaeb70a942015-10-16 21:34:46 -070069 private List<String> deviceCapabilities =
Andrea Campanella1cd641b2015-12-07 17:28:34 -080070 Collections.singletonList("urn:ietf:params:netconf:base:1.0");
andreaeb70a942015-10-16 21:34:46 -070071 private String serverCapabilities;
Andrea Campanella101417d2015-12-11 17:58:07 -080072 private NetconfStreamHandler t;
73 private Map<Integer, CompletableFuture<String>> replies;
Andreas Papazoisd4712e22016-02-10 15:59:55 +020074 private List<String> errorReplies;
andreaeb70a942015-10-16 21:34:46 -070075
76
Andrea Campanella101417d2015-12-11 17:58:07 -080077 public NetconfSessionImpl(NetconfDeviceInfo deviceInfo) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -070078 this.deviceInfo = deviceInfo;
79 connectionActive = false;
Andrea Campanella101417d2015-12-11 17:58:07 -080080 replies = new HashMap<>();
Andreas Papazoisd4712e22016-02-10 15:59:55 +020081 errorReplies = new ArrayList<>();
andreaeb70a942015-10-16 21:34:46 -070082 startConnection();
83 }
84
85
Andrea Campanella101417d2015-12-11 17:58:07 -080086 private void startConnection() throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -070087 if (!connectionActive) {
88 netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port());
Andrea Campanella101417d2015-12-11 17:58:07 -080089 try {
90 netconfConnection.connect(null, CONNECTION_TIMEOUT, 5000);
91 } catch (IOException e) {
92 throw new NetconfException("Cannot open a connection with device" + deviceInfo, e);
93 }
andreaeb70a942015-10-16 21:34:46 -070094 boolean isAuthenticated;
95 try {
96 if (deviceInfo.getKeyFile() != null) {
97 isAuthenticated = netconfConnection.authenticateWithPublicKey(
98 deviceInfo.name(), deviceInfo.getKeyFile(),
99 deviceInfo.password());
100 } else {
Andrea Campanella101417d2015-12-11 17:58:07 -0800101 log.debug("Authenticating to device {} with username {}",
Andrea Campanella50d25212016-02-26 13:06:23 -0800102 deviceInfo.getDeviceId(), deviceInfo.name());
andreaeb70a942015-10-16 21:34:46 -0700103 isAuthenticated = netconfConnection.authenticateWithPassword(
104 deviceInfo.name(), deviceInfo.password());
105 }
106 } catch (IOException e) {
Andrea Campanellad264b492016-03-01 09:46:06 -0800107 log.error("Authentication connection to device {} failed: {} ",
108 deviceInfo.getDeviceId(), e.getMessage());
Andrea Campanella101417d2015-12-11 17:58:07 -0800109 throw new NetconfException("Authentication connection to device " +
110 deviceInfo.getDeviceId() + " failed", e);
andreaeb70a942015-10-16 21:34:46 -0700111 }
112
113 connectionActive = true;
114 Preconditions.checkArgument(isAuthenticated,
Andrea Campanellad264b492016-03-01 09:46:06 -0800115 "Authentication to device %s with username " +
116 "%s failed",
Andrea Campanella50d25212016-02-26 13:06:23 -0800117 deviceInfo.getDeviceId(), deviceInfo.name());
andreaeb70a942015-10-16 21:34:46 -0700118 startSshSession();
119 }
120 }
121
Andrea Campanella101417d2015-12-11 17:58:07 -0800122 private void startSshSession() throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700123 try {
124 sshSession = netconfConnection.openSession();
125 sshSession.startSubSystem("netconf");
Andrea Campanella101417d2015-12-11 17:58:07 -0800126 t = new NetconfStreamThread(sshSession.getStdout(), sshSession.getStdin(),
127 sshSession.getStderr(), deviceInfo,
128 new NetconfSessionDelegateImpl());
129 this.addDeviceOutputListener(new NetconfDeviceOutputEventListenerImpl(deviceInfo));
andreaeb70a942015-10-16 21:34:46 -0700130 sendHello();
131 } catch (IOException e) {
Andrea Campanella1311ea02016-03-04 17:51:25 -0800132 log.error("Failed to create ch.ethz.ssh2.Session session." + e.getMessage());
Andrea Campanella101417d2015-12-11 17:58:07 -0800133 throw new NetconfException("Failed to create ch.ethz.ssh2.Session session with device" +
134 deviceInfo, e);
andreaeb70a942015-10-16 21:34:46 -0700135 }
136 }
137
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800138 private void sendHello() throws NetconfException {
Andrea Campanella101417d2015-12-11 17:58:07 -0800139 serverCapabilities = sendRequest(createHelloString());
andreaeb70a942015-10-16 21:34:46 -0700140 }
141
142 private String createHelloString() {
143 StringBuilder hellobuffer = new StringBuilder();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800144 hellobuffer.append(XML_HEADER);
145 hellobuffer.append("\n");
andreaeb70a942015-10-16 21:34:46 -0700146 hellobuffer.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
147 hellobuffer.append(" <capabilities>\n");
148 deviceCapabilities.forEach(
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800149 cap -> hellobuffer.append(" <capability>")
150 .append(cap)
151 .append("</capability>\n"));
andreaeb70a942015-10-16 21:34:46 -0700152 hellobuffer.append(" </capabilities>\n");
153 hellobuffer.append("</hello>\n");
Andrea Campanella101417d2015-12-11 17:58:07 -0800154 hellobuffer.append(ENDPATTERN);
andreaeb70a942015-10-16 21:34:46 -0700155 return hellobuffer.toString();
156
157 }
158
Andrea Campanella101417d2015-12-11 17:58:07 -0800159 private void checkAndRestablishSession() throws NetconfException {
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800160 if (sshSession.getState() != 2) {
161 try {
162 startSshSession();
163 } catch (IOException e) {
Andrea Campanella101417d2015-12-11 17:58:07 -0800164 log.debug("The connection with {} had to be reopened", deviceInfo.getDeviceId());
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800165 try {
166 startConnection();
167 } catch (IOException e2) {
Andrea Campanella50d25212016-02-26 13:06:23 -0800168 log.error("No connection {} for device", netconfConnection, e2);
Andrea Campanella101417d2015-12-11 17:58:07 -0800169 throw new NetconfException("Cannot re-open the connection with device" + deviceInfo, e);
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800170 }
171 }
172 }
173 }
174
andreaeb70a942015-10-16 21:34:46 -0700175 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800176 public String requestSync(String request) throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800177 if (!request.contains(ENDPATTERN)) {
178 request = request + NEW_LINE + ENDPATTERN;
179 }
180 String reply = sendRequest(request);
Andreas Papazois2e557be2016-06-04 15:39:56 +0300181 checkReply(reply);
182 return reply;
andreaeb70a942015-10-16 21:34:46 -0700183 }
184
185 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800186 public CompletableFuture<String> request(String request) {
187 CompletableFuture<String> ftrep = t.sendMessage(request);
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800188 replies.put(messageIdInteger.get(), ftrep);
Andrea Campanella101417d2015-12-11 17:58:07 -0800189 return ftrep;
190 }
191
192 private String sendRequest(String request) throws NetconfException {
193 checkAndRestablishSession();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800194 request = formatRequestMessageId(request);
195 request = formatXmlHeader(request);
Andrea Campanella101417d2015-12-11 17:58:07 -0800196 CompletableFuture<String> futureReply = request(request);
Andreas Papazoisd4712e22016-02-10 15:59:55 +0200197 messageIdInteger.incrementAndGet();
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300198 int replyTimeout = NetconfControllerImpl.netconfReplyTimeout;
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800199 String rp;
200 try {
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300201 rp = futureReply.get(replyTimeout, TimeUnit.SECONDS);
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800202 } catch (InterruptedException | ExecutionException | TimeoutException e) {
Andreas Papazoisd4712e22016-02-10 15:59:55 +0200203 throw new NetconfException("No matching reply for request " + request, e);
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800204 }
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800205 log.debug("Result {} from request {} to device {}", rp, request, deviceInfo);
Andrea Campanella50d25212016-02-26 13:06:23 -0800206 return rp.trim();
Andrea Campanella101417d2015-12-11 17:58:07 -0800207 }
208
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800209 private String formatRequestMessageId(String request) {
210 if (request.contains(MESSAGE_ID_STRING)) {
211 //FIXME if application provieds his own counting of messages this fails that count
212 request = request.replaceFirst(MESSAGE_ID_STRING + EQUAL + NUMBER_BETWEEN_QUOTES_MATCHER,
213 MESSAGE_ID_STRING + EQUAL + "\"" + messageIdInteger.get() + "\"");
214 } else if (!request.contains(MESSAGE_ID_STRING) && !request.contains(HELLO)) {
215 //FIXME find out a better way to enforce the presence of message-id
216 request = request.replaceFirst(END_OF_RPC_OPEN_TAG, "\" " + MESSAGE_ID_STRING + EQUAL + "\""
217 + messageIdInteger.get() + "\"" + ">");
218 }
219 return request;
220 }
221
222 private String formatXmlHeader(String request) {
223 if (!request.contains(XML_HEADER)) {
224 //FIXME if application provieds his own XML header of different type there is a clash
225 request = XML_HEADER + "\n" + request;
226 }
227 return request;
228 }
229
Andrea Campanella101417d2015-12-11 17:58:07 -0800230 @Override
231 public String get(String request) throws NetconfException {
232 return requestSync(request);
233 }
234
235 @Override
236 public String getConfig(String targetConfiguration) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700237 return getConfig(targetConfiguration, null);
238 }
239
240 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800241 public String getConfig(String targetConfiguration, String configurationSchema) throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800242 StringBuilder rpc = new StringBuilder(XML_HEADER);
243 rpc.append("<rpc ");
244 rpc.append(MESSAGE_ID_STRING);
245 rpc.append(EQUAL);
246 rpc.append("\"");
247 rpc.append(messageIdInteger.get());
248 rpc.append("\" ");
249 rpc.append("xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
andreaeb70a942015-10-16 21:34:46 -0700250 rpc.append("<get-config>\n");
251 rpc.append("<source>\n");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800252 rpc.append("<").append(targetConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700253 rpc.append("</source>");
254 if (configurationSchema != null) {
255 rpc.append("<filter type=\"subtree\">\n");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800256 rpc.append(configurationSchema).append("\n");
andreaeb70a942015-10-16 21:34:46 -0700257 rpc.append("</filter>\n");
258 }
259 rpc.append("</get-config>\n");
260 rpc.append("</rpc>\n");
Andrea Campanella101417d2015-12-11 17:58:07 -0800261 rpc.append(ENDPATTERN);
262 String reply = sendRequest(rpc.toString());
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800263 return checkReply(reply) ? reply : "ERROR " + reply;
andreaeb70a942015-10-16 21:34:46 -0700264 }
265
266 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800267 public boolean editConfig(String newConfiguration) throws NetconfException {
268 newConfiguration = newConfiguration + ENDPATTERN;
269 return checkReply(sendRequest(newConfiguration));
andreaeb70a942015-10-16 21:34:46 -0700270 }
271
272 @Override
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800273 public boolean editConfig(String targetConfiguration, String mode, String newConfiguration)
Andrea Campanella101417d2015-12-11 17:58:07 -0800274 throws NetconfException {
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800275 newConfiguration = newConfiguration.trim();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800276 StringBuilder rpc = new StringBuilder(XML_HEADER);
277 rpc.append("<rpc ");
278 rpc.append(MESSAGE_ID_STRING);
279 rpc.append(EQUAL);
280 rpc.append("\"");
281 rpc.append(messageIdInteger.get());
282 rpc.append("\" ");
283 rpc.append("xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
Andrea Campanella50d25212016-02-26 13:06:23 -0800284 rpc.append("<edit-config>\n");
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800285 rpc.append("<target>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800286 rpc.append("<").append(targetConfiguration).append("/>");
Andrea Campanella50d25212016-02-26 13:06:23 -0800287 rpc.append("</target>\n");
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800288 rpc.append("<default-operation>");
289 rpc.append(mode);
Andrea Campanella50d25212016-02-26 13:06:23 -0800290 rpc.append("</default-operation>\n");
291 rpc.append("<config>\n");
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800292 rpc.append(newConfiguration);
Andrea Campanella50d25212016-02-26 13:06:23 -0800293 rpc.append("</config>\n");
294 rpc.append("</edit-config>\n");
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800295 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800296 rpc.append(ENDPATTERN);
Andrea Campanella50d25212016-02-26 13:06:23 -0800297 log.info(rpc.toString());
Andrea Campanella101417d2015-12-11 17:58:07 -0800298 return checkReply(sendRequest(rpc.toString()));
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800299 }
300
301 @Override
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800302 public boolean copyConfig(String targetConfiguration, String newConfiguration)
Andrea Campanella101417d2015-12-11 17:58:07 -0800303 throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700304 newConfiguration = newConfiguration.trim();
305 if (!newConfiguration.startsWith("<configuration>")) {
306 newConfiguration = "<configuration>" + newConfiguration
307 + "</configuration>";
308 }
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800309 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700310 rpc.append("<rpc>");
311 rpc.append("<copy-config>");
312 rpc.append("<target>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800313 rpc.append("<").append(targetConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700314 rpc.append("</target>");
315 rpc.append("<source>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800316 rpc.append("<").append(newConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700317 rpc.append("</source>");
318 rpc.append("</copy-config>");
319 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800320 rpc.append(ENDPATTERN);
321 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700322 }
323
324 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800325 public boolean deleteConfig(String targetConfiguration) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700326 if (targetConfiguration.equals("running")) {
327 log.warn("Target configuration for delete operation can't be \"running\"",
328 targetConfiguration);
329 return false;
330 }
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800331 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700332 rpc.append("<rpc>");
333 rpc.append("<delete-config>");
334 rpc.append("<target>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800335 rpc.append("<").append(targetConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700336 rpc.append("</target>");
337 rpc.append("</delete-config>");
338 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800339 rpc.append(ENDPATTERN);
340 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700341 }
342
343 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800344 public boolean lock() throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800345 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700346 rpc.append("<rpc>");
347 rpc.append("<lock>");
348 rpc.append("<target>");
349 rpc.append("<candidate/>");
350 rpc.append("</target>");
351 rpc.append("</lock>");
352 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800353 rpc.append(ENDPATTERN);
354 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700355 }
356
357 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800358 public boolean unlock() throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800359 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700360 rpc.append("<rpc>");
361 rpc.append("<unlock>");
362 rpc.append("<target>");
363 rpc.append("<candidate/>");
364 rpc.append("</target>");
365 rpc.append("</unlock>");
366 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800367 rpc.append(ENDPATTERN);
368 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700369 }
370
371 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800372 public boolean close() throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700373 return close(false);
374 }
375
Andrea Campanella101417d2015-12-11 17:58:07 -0800376 private boolean close(boolean force) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700377 StringBuilder rpc = new StringBuilder();
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700378 rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
andreaeb70a942015-10-16 21:34:46 -0700379 if (force) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700380 rpc.append("<kill-session/>");
andreaeb70a942015-10-16 21:34:46 -0700381 } else {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700382 rpc.append("<close-session/>");
andreaeb70a942015-10-16 21:34:46 -0700383 }
andreaeb70a942015-10-16 21:34:46 -0700384 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800385 rpc.append(ENDPATTERN);
386 return checkReply(sendRequest(rpc.toString())) || close(true);
andreaeb70a942015-10-16 21:34:46 -0700387 }
388
389 @Override
390 public String getSessionId() {
391 if (serverCapabilities.contains("<session-id>")) {
392 String[] outer = serverCapabilities.split("<session-id>");
393 Preconditions.checkArgument(outer.length != 1,
394 "Error in retrieving the session id");
395 String[] value = outer[1].split("</session-id>");
396 Preconditions.checkArgument(value.length != 1,
397 "Error in retrieving the session id");
398 return value[0];
399 } else {
400 return String.valueOf(-1);
401 }
402 }
403
404 @Override
405 public String getServerCapabilities() {
406 return serverCapabilities;
407 }
408
409 @Override
410 public void setDeviceCapabilities(List<String> capabilities) {
411 deviceCapabilities = capabilities;
412 }
413
Andrea Campanella101417d2015-12-11 17:58:07 -0800414 @Override
415 public void addDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
416 t.addDeviceEventListener(listener);
417 }
418
419 @Override
420 public void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
421 t.removeDeviceEventListener(listener);
422 }
423
424 private boolean checkReply(String reply) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700425 if (reply != null) {
426 if (!reply.contains("<rpc-error>")) {
427 return true;
428 } else if (reply.contains("<ok/>")
429 || (reply.contains("<rpc-error>")
430 && reply.contains("warning"))) {
431 return true;
432 }
433 }
Andrea Campanellad264b492016-03-01 09:46:06 -0800434 log.warn("Device {} has error in reply {}", deviceInfo, reply);
andreaeb70a942015-10-16 21:34:46 -0700435 return false;
436 }
437
Andrea Campanella101417d2015-12-11 17:58:07 -0800438 public class NetconfSessionDelegateImpl implements NetconfSessionDelegate {
andreaeb70a942015-10-16 21:34:46 -0700439
Andrea Campanella101417d2015-12-11 17:58:07 -0800440 @Override
Andreas Papazoisd4712e22016-02-10 15:59:55 +0200441 public void notify(NetconfDeviceOutputEvent event) {
442 Optional<Integer> messageId = event.getMessageID();
443 if (!messageId.isPresent()) {
444 errorReplies.add(event.getMessagePayload());
Andrea Campanellad264b492016-03-01 09:46:06 -0800445 log.error("Device {} sent error reply {}",
446 event.getDeviceInfo(), event.getMessagePayload());
Andreas Papazoisd4712e22016-02-10 15:59:55 +0200447 return;
448 }
449 CompletableFuture<String> completedReply =
450 replies.get(messageId.get());
Andrea Campanella101417d2015-12-11 17:58:07 -0800451 completedReply.complete(event.getMessagePayload());
andreaeb70a942015-10-16 21:34:46 -0700452 }
453 }
andreaeb70a942015-10-16 21:34:46 -0700454}