blob: 9f4b47ab19a4c98a49653ed2877ce48d0e010bbd [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 int FUTURE_REPLY_TIMEOUT = 5000;
59 private static final String ERROR = "ERROR ";
60 private static final String END_OF_RPC_OPEN_TAG = "\">";
61 private static final String EQUAL = "=";
62 private static final String NUMBER_BETWEEN_QUOTES_MATCHER = "\"+([0-9]+)+\"";
63 private static final String XML_HEADER =
64 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
andreaeb70a942015-10-16 21:34:46 -070065
Andrea Campanellab029b9e2016-01-29 11:05:36 -080066 private final AtomicInteger messageIdInteger = new AtomicInteger(0);
andreaeb70a942015-10-16 21:34:46 -070067 private Connection netconfConnection;
68 private NetconfDeviceInfo deviceInfo;
69 private Session sshSession;
70 private boolean connectionActive;
andreaeb70a942015-10-16 21:34:46 -070071 private List<String> deviceCapabilities =
Andrea Campanella1cd641b2015-12-07 17:28:34 -080072 Collections.singletonList("urn:ietf:params:netconf:base:1.0");
andreaeb70a942015-10-16 21:34:46 -070073 private String serverCapabilities;
Andrea Campanella101417d2015-12-11 17:58:07 -080074 private NetconfStreamHandler t;
75 private Map<Integer, CompletableFuture<String>> replies;
Andreas Papazoisd4712e22016-02-10 15:59:55 +020076 private List<String> errorReplies;
andreaeb70a942015-10-16 21:34:46 -070077
78
Andrea Campanella101417d2015-12-11 17:58:07 -080079 public NetconfSessionImpl(NetconfDeviceInfo deviceInfo) throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -070080 this.deviceInfo = deviceInfo;
81 connectionActive = false;
Andrea Campanella101417d2015-12-11 17:58:07 -080082 replies = new HashMap<>();
Andreas Papazoisd4712e22016-02-10 15:59:55 +020083 errorReplies = new ArrayList<>();
andreaeb70a942015-10-16 21:34:46 -070084 startConnection();
85 }
86
87
Andrea Campanella101417d2015-12-11 17:58:07 -080088 private void startConnection() throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -070089 if (!connectionActive) {
90 netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port());
Andrea Campanella101417d2015-12-11 17:58:07 -080091 try {
92 netconfConnection.connect(null, CONNECTION_TIMEOUT, 5000);
93 } catch (IOException e) {
94 throw new NetconfException("Cannot open a connection with device" + deviceInfo, e);
95 }
andreaeb70a942015-10-16 21:34:46 -070096 boolean isAuthenticated;
97 try {
98 if (deviceInfo.getKeyFile() != null) {
99 isAuthenticated = netconfConnection.authenticateWithPublicKey(
100 deviceInfo.name(), deviceInfo.getKeyFile(),
101 deviceInfo.password());
102 } else {
Andrea Campanella101417d2015-12-11 17:58:07 -0800103 log.debug("Authenticating to device {} with username {}",
Andrea Campanella50d25212016-02-26 13:06:23 -0800104 deviceInfo.getDeviceId(), deviceInfo.name());
andreaeb70a942015-10-16 21:34:46 -0700105 isAuthenticated = netconfConnection.authenticateWithPassword(
106 deviceInfo.name(), deviceInfo.password());
107 }
108 } catch (IOException e) {
Andrea Campanellad264b492016-03-01 09:46:06 -0800109 log.error("Authentication connection to device {} failed: {} ",
110 deviceInfo.getDeviceId(), e.getMessage());
Andrea Campanella101417d2015-12-11 17:58:07 -0800111 throw new NetconfException("Authentication connection to device " +
112 deviceInfo.getDeviceId() + " failed", e);
andreaeb70a942015-10-16 21:34:46 -0700113 }
114
115 connectionActive = true;
116 Preconditions.checkArgument(isAuthenticated,
Andrea Campanellad264b492016-03-01 09:46:06 -0800117 "Authentication to device %s with username " +
118 "%s failed",
Andrea Campanella50d25212016-02-26 13:06:23 -0800119 deviceInfo.getDeviceId(), deviceInfo.name());
andreaeb70a942015-10-16 21:34:46 -0700120 startSshSession();
121 }
122 }
123
Andrea Campanella101417d2015-12-11 17:58:07 -0800124 private void startSshSession() throws NetconfException {
andreaeb70a942015-10-16 21:34:46 -0700125 try {
126 sshSession = netconfConnection.openSession();
127 sshSession.startSubSystem("netconf");
Andrea Campanella101417d2015-12-11 17:58:07 -0800128 t = new NetconfStreamThread(sshSession.getStdout(), sshSession.getStdin(),
129 sshSession.getStderr(), deviceInfo,
130 new NetconfSessionDelegateImpl());
131 this.addDeviceOutputListener(new NetconfDeviceOutputEventListenerImpl(deviceInfo));
andreaeb70a942015-10-16 21:34:46 -0700132 sendHello();
133 } catch (IOException e) {
Andrea Campanella1311ea02016-03-04 17:51:25 -0800134 log.error("Failed to create ch.ethz.ssh2.Session session." + e.getMessage());
Andrea Campanella101417d2015-12-11 17:58:07 -0800135 throw new NetconfException("Failed to create ch.ethz.ssh2.Session session with device" +
136 deviceInfo, e);
andreaeb70a942015-10-16 21:34:46 -0700137 }
138 }
139
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800140 private void sendHello() throws NetconfException {
Andrea Campanella101417d2015-12-11 17:58:07 -0800141 serverCapabilities = sendRequest(createHelloString());
andreaeb70a942015-10-16 21:34:46 -0700142 }
143
144 private String createHelloString() {
145 StringBuilder hellobuffer = new StringBuilder();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800146 hellobuffer.append(XML_HEADER);
147 hellobuffer.append("\n");
andreaeb70a942015-10-16 21:34:46 -0700148 hellobuffer.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
149 hellobuffer.append(" <capabilities>\n");
150 deviceCapabilities.forEach(
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800151 cap -> hellobuffer.append(" <capability>")
152 .append(cap)
153 .append("</capability>\n"));
andreaeb70a942015-10-16 21:34:46 -0700154 hellobuffer.append(" </capabilities>\n");
155 hellobuffer.append("</hello>\n");
Andrea Campanella101417d2015-12-11 17:58:07 -0800156 hellobuffer.append(ENDPATTERN);
andreaeb70a942015-10-16 21:34:46 -0700157 return hellobuffer.toString();
158
159 }
160
Andrea Campanella101417d2015-12-11 17:58:07 -0800161 private void checkAndRestablishSession() throws NetconfException {
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800162 if (sshSession.getState() != 2) {
163 try {
164 startSshSession();
165 } catch (IOException e) {
Andrea Campanella101417d2015-12-11 17:58:07 -0800166 log.debug("The connection with {} had to be reopened", deviceInfo.getDeviceId());
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800167 try {
168 startConnection();
169 } catch (IOException e2) {
Andrea Campanella50d25212016-02-26 13:06:23 -0800170 log.error("No connection {} for device", netconfConnection, e2);
Andrea Campanella101417d2015-12-11 17:58:07 -0800171 throw new NetconfException("Cannot re-open the connection with device" + deviceInfo, e);
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800172 }
173 }
174 }
175 }
176
andreaeb70a942015-10-16 21:34:46 -0700177 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800178 public String requestSync(String request) throws NetconfException {
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800179 if (!request.contains(ENDPATTERN)) {
180 request = request + NEW_LINE + ENDPATTERN;
181 }
182 String reply = sendRequest(request);
183 return checkReply(reply) ? reply : ERROR + reply;
andreaeb70a942015-10-16 21:34:46 -0700184 }
185
186 @Override
Andrea Campanella101417d2015-12-11 17:58:07 -0800187 public CompletableFuture<String> request(String request) {
188 CompletableFuture<String> ftrep = t.sendMessage(request);
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800189 replies.put(messageIdInteger.get(), ftrep);
Andrea Campanella101417d2015-12-11 17:58:07 -0800190 return ftrep;
191 }
192
193 private String sendRequest(String request) throws NetconfException {
194 checkAndRestablishSession();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800195 request = formatRequestMessageId(request);
196 request = formatXmlHeader(request);
Andrea Campanella101417d2015-12-11 17:58:07 -0800197 CompletableFuture<String> futureReply = request(request);
Andreas Papazoisd4712e22016-02-10 15:59:55 +0200198 messageIdInteger.incrementAndGet();
Andrea Campanellab029b9e2016-01-29 11:05:36 -0800199 String rp;
200 try {
201 rp = futureReply.get(FUTURE_REPLY_TIMEOUT, TimeUnit.MILLISECONDS);
202 } 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}