blob: 9a950fbd70eb4f58c982a13424adea6b81869f12 [file] [log] [blame]
andreaeb70a942015-10-16 21:34:46 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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;
Andrea Campanella1cd641b2015-12-07 17:28:34 -080031import java.util.Collections;
Andrea Campanella101417d2015-12-11 17:58:07 -080032import java.util.HashMap;
andreaeb70a942015-10-16 21:34:46 -070033import java.util.List;
Andrea Campanella101417d2015-12-11 17:58:07 -080034import java.util.Map;
35import java.util.concurrent.CompletableFuture;
Andrea Campanellab029b9e2016-01-29 11:05:36 -080036import java.util.concurrent.ExecutionException;
37import java.util.concurrent.TimeUnit;
38import java.util.concurrent.TimeoutException;
Andrea Campanella101417d2015-12-11 17:58:07 -080039import java.util.concurrent.atomic.AtomicInteger;
40
andreaeb70a942015-10-16 21:34:46 -070041
42/**
43 * Implementation of a NETCONF session to talk to a device.
44 */
45public class NetconfSessionImpl implements NetconfSession {
46
Andrea Campanella101417d2015-12-11 17:58:07 -080047 private static final Logger log = LoggerFactory
andreaeb70a942015-10-16 21:34:46 -070048 .getLogger(NetconfSessionImpl.class);
Andrea Campanella101417d2015-12-11 17:58:07 -080049
50
andreaeb70a942015-10-16 21:34:46 -070051 private static final int CONNECTION_TIMEOUT = 0;
Andrea Campanella101417d2015-12-11 17:58:07 -080052 private static final String ENDPATTERN = "]]>]]>";
Andrea Campanella101417d2015-12-11 17:58:07 -080053 private static final String MESSAGE_ID_STRING = "message-id";
54 private static final String HELLO = "hello";
55 private static final String NEW_LINE = "\n";
Andrea Campanellab029b9e2016-01-29 11:05:36 -080056 private static final int FUTURE_REPLY_TIMEOUT = 5000;
57 private static final String ERROR = "ERROR ";
58 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;
andreaeb70a942015-10-16 21:34:46 -070074
75
Andrea Campanella101417d2015-12-11 17:58:07 -080076 public NetconfSessionImpl(NetconfDeviceInfo deviceInfo) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -070077 this.deviceInfo = deviceInfo;
78 connectionActive = false;
Andrea Campanella101417d2015-12-11 17:58:07 -080079 replies = new HashMap<>();
andreaeb70a942015-10-16 21:34:46 -070080 startConnection();
81 }
82
83
Andrea Campanella101417d2015-12-11 17:58:07 -080084 private void startConnection() throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -070085 if (!connectionActive) {
86 netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port());
Andrea Campanella101417d2015-12-11 17:58:07 -080087 try {
88 netconfConnection.connect(null, CONNECTION_TIMEOUT, 5000);
89 } catch (IOException e) {
90 throw new NetconfException("Cannot open a connection with device" + deviceInfo, e);
91 }
andreaeb70a942015-10-16 21:34:46 -070092 boolean isAuthenticated;
93 try {
94 if (deviceInfo.getKeyFile() != null) {
95 isAuthenticated = netconfConnection.authenticateWithPublicKey(
96 deviceInfo.name(), deviceInfo.getKeyFile(),
97 deviceInfo.password());
98 } else {
Andrea Campanella101417d2015-12-11 17:58:07 -080099 log.debug("Authenticating to device {} with username {}",
100 deviceInfo.getDeviceId(), deviceInfo.name(), deviceInfo.password());
andreaeb70a942015-10-16 21:34:46 -0700101 isAuthenticated = netconfConnection.authenticateWithPassword(
102 deviceInfo.name(), deviceInfo.password());
103 }
104 } catch (IOException e) {
Andrea Campanella101417d2015-12-11 17:58:07 -0800105 log.error("Authentication connection to device " +
106 deviceInfo.getDeviceId() + " failed:" +
107 e.getMessage());
108 throw new NetconfException("Authentication connection to device " +
109 deviceInfo.getDeviceId() + " failed", e);
andreaeb70a942015-10-16 21:34:46 -0700110 }
111
112 connectionActive = true;
113 Preconditions.checkArgument(isAuthenticated,
Andrea Campanella101417d2015-12-11 17:58:07 -0800114 "Authentication to device {} with username " +
115 "{} Failed",
116 deviceInfo.getDeviceId(), deviceInfo.name(),
117 deviceInfo.password());
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 Campanella101417d2015-12-11 17:58:07 -0800132 log.error("Failed to create ch.ethz.ssh2.Session session:" +
133 e.getMessage());
134 throw new NetconfException("Failed to create ch.ethz.ssh2.Session session with device" +
135 deviceInfo, e);
andreaeb70a942015-10-16 21:34:46 -0700136 }
137 }
138
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800139 private void sendHello() throws NetconfException {
Andrea Campanella101417d2015-12-11 17:58:07 -0800140 serverCapabilities = sendRequest(createHelloString());
andreaeb70a942015-10-16 21:34:46 -0700141 }
142
143 private String createHelloString() {
144 StringBuilder hellobuffer = new StringBuilder();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800145 hellobuffer.append(XML_HEADER);
146 hellobuffer.append("\n");
andreaeb70a942015-10-16 21:34:46 -0700147 hellobuffer.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
148 hellobuffer.append(" <capabilities>\n");
149 deviceCapabilities.forEach(
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800150 cap -> hellobuffer.append(" <capability>")
151 .append(cap)
152 .append("</capability>\n"));
andreaeb70a942015-10-16 21:34:46 -0700153 hellobuffer.append(" </capabilities>\n");
154 hellobuffer.append("</hello>\n");
Andrea Campanella101417d2015-12-11 17:58:07 -0800155 hellobuffer.append(ENDPATTERN);
andreaeb70a942015-10-16 21:34:46 -0700156 return hellobuffer.toString();
157
158 }
159
Andrea Campanella101417d2015-12-11 17:58:07 -0800160 private void checkAndRestablishSession() throws NetconfException {
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800161 if (sshSession.getState() != 2) {
162 try {
163 startSshSession();
164 } catch (IOException e) {
Andrea Campanella101417d2015-12-11 17:58:07 -0800165 log.debug("The connection with {} had to be reopened", deviceInfo.getDeviceId());
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800166 try {
167 startConnection();
168 } catch (IOException e2) {
169 log.error("No connection {} for device, exception {}", netconfConnection, e2);
Andrea Campanella101417d2015-12-11 17:58:07 -0800170 throw new NetconfException("Cannot re-open the connection with device" + deviceInfo, e);
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800171 }
172 }
173 }
174 }
175
andreaeb70a942015-10-16 21:34:46 -0700176 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800177 public String requestSync(String request) throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800178 if (!request.contains(ENDPATTERN)) {
179 request = request + NEW_LINE + ENDPATTERN;
180 }
181 String reply = sendRequest(request);
182 return checkReply(reply) ? reply : ERROR + 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);
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800197 String rp;
198 try {
199 rp = futureReply.get(FUTURE_REPLY_TIMEOUT, TimeUnit.MILLISECONDS);
200 } catch (InterruptedException | ExecutionException | TimeoutException e) {
201 //replies.remove(messageIdInteger.get());
202 throw new NetconfException("Can't get the reply for request" + request, e);
203 }
204// String rp = Tools.futureGetOrElse(futureReply, FUTURE_REPLY_TIMEOUT, TimeUnit.MILLISECONDS,
205// "Error in completing the request with message-id " +
206// messageIdInteger.get() +
207// ": future timed out.");
208 messageIdInteger.incrementAndGet();
209 log.debug("Result {} from request {} to device {}", rp, request, deviceInfo);
Andrea Campanella101417d2015-12-11 17:58:07 -0800210 return rp;
211 }
212
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800213 private String formatRequestMessageId(String request) {
214 if (request.contains(MESSAGE_ID_STRING)) {
215 //FIXME if application provieds his own counting of messages this fails that count
216 request = request.replaceFirst(MESSAGE_ID_STRING + EQUAL + NUMBER_BETWEEN_QUOTES_MATCHER,
217 MESSAGE_ID_STRING + EQUAL + "\"" + messageIdInteger.get() + "\"");
218 } else if (!request.contains(MESSAGE_ID_STRING) && !request.contains(HELLO)) {
219 //FIXME find out a better way to enforce the presence of message-id
220 request = request.replaceFirst(END_OF_RPC_OPEN_TAG, "\" " + MESSAGE_ID_STRING + EQUAL + "\""
221 + messageIdInteger.get() + "\"" + ">");
222 }
223 return request;
224 }
225
226 private String formatXmlHeader(String request) {
227 if (!request.contains(XML_HEADER)) {
228 //FIXME if application provieds his own XML header of different type there is a clash
229 request = XML_HEADER + "\n" + request;
230 }
231 return request;
232 }
233
Andrea Campanella101417d2015-12-11 17:58:07 -0800234 @Override
235 public String get(String request) throws NetconfException {
236 return requestSync(request);
237 }
238
239 @Override
240 public String getConfig(String targetConfiguration) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700241 return getConfig(targetConfiguration, null);
242 }
243
244 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800245 public String getConfig(String targetConfiguration, String configurationSchema) throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800246 StringBuilder rpc = new StringBuilder(XML_HEADER);
247 rpc.append("<rpc ");
248 rpc.append(MESSAGE_ID_STRING);
249 rpc.append(EQUAL);
250 rpc.append("\"");
251 rpc.append(messageIdInteger.get());
252 rpc.append("\" ");
253 rpc.append("xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
andreaeb70a942015-10-16 21:34:46 -0700254 rpc.append("<get-config>\n");
255 rpc.append("<source>\n");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800256 rpc.append("<").append(targetConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700257 rpc.append("</source>");
258 if (configurationSchema != null) {
259 rpc.append("<filter type=\"subtree\">\n");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800260 rpc.append(configurationSchema).append("\n");
andreaeb70a942015-10-16 21:34:46 -0700261 rpc.append("</filter>\n");
262 }
263 rpc.append("</get-config>\n");
264 rpc.append("</rpc>\n");
Andrea Campanella101417d2015-12-11 17:58:07 -0800265 rpc.append(ENDPATTERN);
266 String reply = sendRequest(rpc.toString());
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800267 return checkReply(reply) ? reply : "ERROR " + reply;
andreaeb70a942015-10-16 21:34:46 -0700268 }
269
270 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800271 public boolean editConfig(String newConfiguration) throws NetconfException {
272 newConfiguration = newConfiguration + ENDPATTERN;
273 return checkReply(sendRequest(newConfiguration));
andreaeb70a942015-10-16 21:34:46 -0700274 }
275
276 @Override
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800277 public boolean editConfig(String targetConfiguration, String mode, String newConfiguration)
Andrea Campanella101417d2015-12-11 17:58:07 -0800278 throws NetconfException {
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800279 newConfiguration = newConfiguration.trim();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800280 StringBuilder rpc = new StringBuilder(XML_HEADER);
281 rpc.append("<rpc ");
282 rpc.append(MESSAGE_ID_STRING);
283 rpc.append(EQUAL);
284 rpc.append("\"");
285 rpc.append(messageIdInteger.get());
286 rpc.append("\" ");
287 rpc.append("xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800288 rpc.append("<edit-config>");
289 rpc.append("<target>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800290 rpc.append("<").append(targetConfiguration).append("/>");
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800291 rpc.append("</target>");
292 rpc.append("<default-operation>");
293 rpc.append(mode);
294 rpc.append("</default-operation>");
295 rpc.append("<config>");
296 rpc.append(newConfiguration);
297 rpc.append("</config>");
298 rpc.append("</edit-config>");
299 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800300 rpc.append(ENDPATTERN);
301 return checkReply(sendRequest(rpc.toString()));
Andrea Campanellaf4fd0352015-12-14 17:03:05 -0800302 }
303
304 @Override
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800305 public boolean copyConfig(String targetConfiguration, String newConfiguration)
Andrea Campanella101417d2015-12-11 17:58:07 -0800306 throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700307 newConfiguration = newConfiguration.trim();
308 if (!newConfiguration.startsWith("<configuration>")) {
309 newConfiguration = "<configuration>" + newConfiguration
310 + "</configuration>";
311 }
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800312 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700313 rpc.append("<rpc>");
314 rpc.append("<copy-config>");
315 rpc.append("<target>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800316 rpc.append("<").append(targetConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700317 rpc.append("</target>");
318 rpc.append("<source>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800319 rpc.append("<").append(newConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700320 rpc.append("</source>");
321 rpc.append("</copy-config>");
322 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800323 rpc.append(ENDPATTERN);
324 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700325 }
326
327 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800328 public boolean deleteConfig(String targetConfiguration) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700329 if (targetConfiguration.equals("running")) {
330 log.warn("Target configuration for delete operation can't be \"running\"",
331 targetConfiguration);
332 return false;
333 }
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800334 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700335 rpc.append("<rpc>");
336 rpc.append("<delete-config>");
337 rpc.append("<target>");
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800338 rpc.append("<").append(targetConfiguration).append("/>");
andreaeb70a942015-10-16 21:34:46 -0700339 rpc.append("</target>");
340 rpc.append("</delete-config>");
341 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800342 rpc.append(ENDPATTERN);
343 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700344 }
345
346 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800347 public boolean lock() throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800348 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700349 rpc.append("<rpc>");
350 rpc.append("<lock>");
351 rpc.append("<target>");
352 rpc.append("<candidate/>");
353 rpc.append("</target>");
354 rpc.append("</lock>");
355 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800356 rpc.append(ENDPATTERN);
357 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700358 }
359
360 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800361 public boolean unlock() throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800362 StringBuilder rpc = new StringBuilder(XML_HEADER);
andreaeb70a942015-10-16 21:34:46 -0700363 rpc.append("<rpc>");
364 rpc.append("<unlock>");
365 rpc.append("<target>");
366 rpc.append("<candidate/>");
367 rpc.append("</target>");
368 rpc.append("</unlock>");
369 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800370 rpc.append(ENDPATTERN);
371 return checkReply(sendRequest(rpc.toString()));
andreaeb70a942015-10-16 21:34:46 -0700372 }
373
374 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800375 public boolean close() throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700376 return close(false);
377 }
378
Andrea Campanella101417d2015-12-11 17:58:07 -0800379 private boolean close(boolean force) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700380 StringBuilder rpc = new StringBuilder();
381 rpc.append("<rpc>");
382 if (force) {
383 rpc.append("<kill-configuration/>");
384 } else {
385 rpc.append("<close-configuration/>");
386 }
387 rpc.append("<close-configuration/>");
388 rpc.append("</rpc>");
Andrea Campanella101417d2015-12-11 17:58:07 -0800389 rpc.append(ENDPATTERN);
390 return checkReply(sendRequest(rpc.toString())) || close(true);
andreaeb70a942015-10-16 21:34:46 -0700391 }
392
393 @Override
394 public String getSessionId() {
395 if (serverCapabilities.contains("<session-id>")) {
396 String[] outer = serverCapabilities.split("<session-id>");
397 Preconditions.checkArgument(outer.length != 1,
398 "Error in retrieving the session id");
399 String[] value = outer[1].split("</session-id>");
400 Preconditions.checkArgument(value.length != 1,
401 "Error in retrieving the session id");
402 return value[0];
403 } else {
404 return String.valueOf(-1);
405 }
406 }
407
408 @Override
409 public String getServerCapabilities() {
410 return serverCapabilities;
411 }
412
413 @Override
414 public void setDeviceCapabilities(List<String> capabilities) {
415 deviceCapabilities = capabilities;
416 }
417
Andrea Campanella101417d2015-12-11 17:58:07 -0800418 @Override
419 public void addDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
420 t.addDeviceEventListener(listener);
421 }
422
423 @Override
424 public void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
425 t.removeDeviceEventListener(listener);
426 }
427
428 private boolean checkReply(String reply) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700429 if (reply != null) {
430 if (!reply.contains("<rpc-error>")) {
431 return true;
432 } else if (reply.contains("<ok/>")
433 || (reply.contains("<rpc-error>")
434 && reply.contains("warning"))) {
435 return true;
436 }
437 }
Andrea Campanella101417d2015-12-11 17:58:07 -0800438 log.warn("Device " + deviceInfo + "has error in reply {}", reply);
andreaeb70a942015-10-16 21:34:46 -0700439 return false;
440 }
441
Andrea Campanella101417d2015-12-11 17:58:07 -0800442 public class NetconfSessionDelegateImpl implements NetconfSessionDelegate {
andreaeb70a942015-10-16 21:34:46 -0700443
Andrea Campanella101417d2015-12-11 17:58:07 -0800444 @Override
445 public void notify(NetconfDeviceOutputEvent event) {
446 CompletableFuture<String> completedReply = replies.get(event.getMessageID());
447 completedReply.complete(event.getMessagePayload());
andreaeb70a942015-10-16 21:34:46 -0700448 }
449 }
andreaeb70a942015-10-16 21:34:46 -0700450}