blob: 0747f8fa819c0aff104be1e935420283534e0a4b [file] [log] [blame]
Yuta HIGUCHI348b3232017-04-20 10:19:48 -07001/*
2 * Copyright 2015-present 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 org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Modified;
23import org.apache.felix.scr.annotations.Property;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.packet.IpAddress;
28import org.onosproject.cfg.ComponentConfigService;
29import org.onosproject.net.AnnotationKeys;
30import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.key.DeviceKey;
34import org.onosproject.net.key.DeviceKeyId;
35import org.onosproject.net.key.DeviceKeyService;
36import org.onosproject.net.key.UsernamePassword;
37import org.onosproject.netconf.NetconfController;
38import org.onosproject.netconf.NetconfDevice;
39import org.onosproject.netconf.NetconfDeviceFactory;
40import org.onosproject.netconf.NetconfDeviceInfo;
41import org.onosproject.netconf.NetconfDeviceListener;
42import org.onosproject.netconf.NetconfDeviceOutputEvent;
43import org.onosproject.netconf.NetconfDeviceOutputEventListener;
44import org.onosproject.netconf.NetconfException;
45import org.osgi.service.component.ComponentContext;
46import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
49import java.util.Arrays;
50import java.util.Dictionary;
51import java.util.Map;
52import java.util.Set;
53import java.util.concurrent.ConcurrentHashMap;
54import java.util.concurrent.CopyOnWriteArraySet;
55import java.util.concurrent.ExecutorService;
56import java.util.concurrent.Executors;
57
58import static com.google.common.base.Strings.isNullOrEmpty;
59import static org.onlab.util.Tools.get;
60import static org.onlab.util.Tools.groupedThreads;
61
62/**
63 * The implementation of NetconfController.
64 *
65 * @deprecated in 1.10.0
66 */
67@Deprecated
68@Component(immediate = false, enabled = false)
69@Service
70public class NetconfControllerImpl implements NetconfController {
71 private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 5;
72 private static final String PROP_NETCONF_CONNECT_TIMEOUT = "netconfConnectTimeout";
73 @Property(name = PROP_NETCONF_CONNECT_TIMEOUT, intValue = DEFAULT_CONNECT_TIMEOUT_SECONDS,
74 label = "Time (in seconds) to wait for a NETCONF connect.")
75 protected static int netconfConnectTimeout = DEFAULT_CONNECT_TIMEOUT_SECONDS;
76
77 private static final String PROP_NETCONF_REPLY_TIMEOUT = "netconfReplyTimeout";
78 private static final int DEFAULT_REPLY_TIMEOUT_SECONDS = 5;
79 @Property(name = PROP_NETCONF_REPLY_TIMEOUT, intValue = DEFAULT_REPLY_TIMEOUT_SECONDS,
80 label = "Time (in seconds) waiting for a NetConf reply")
81 protected static int netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected ComponentConfigService cfgService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected DeviceService deviceService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected DeviceKeyService deviceKeyService;
91
92 public static final Logger log = LoggerFactory
93 .getLogger(NetconfControllerImpl.class);
94
95 private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<>();
96
97 private final NetconfDeviceOutputEventListener downListener = new DeviceDownEventListener();
98
99 protected Set<NetconfDeviceListener> netconfDeviceListeners = new CopyOnWriteArraySet<>();
100 protected NetconfDeviceFactory deviceFactory = new DefaultNetconfDeviceFactory();
101
102 protected final ExecutorService executor =
103 Executors.newCachedThreadPool(groupedThreads("onos/netconfdevicecontroller",
104 "connection-reopen-%d", log));
105
106 @Activate
107 public void activate(ComponentContext context) {
108 cfgService.registerProperties(getClass());
109 modified(context);
110 log.info("Started");
111 }
112
113 @Deactivate
114 public void deactivate() {
115 cfgService.unregisterProperties(getClass(), false);
116 netconfDeviceMap.clear();
117 log.info("Stopped");
118 }
119
120 @Modified
121 public void modified(ComponentContext context) {
122 if (context == null) {
123 netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
124 netconfConnectTimeout = DEFAULT_CONNECT_TIMEOUT_SECONDS;
125 log.info("No component configuration");
126 return;
127 }
128
129 Dictionary<?, ?> properties = context.getProperties();
130
131 int newNetconfReplyTimeout;
132 int newNetconfConnectTimeout;
133 try {
134 String s = get(properties, PROP_NETCONF_REPLY_TIMEOUT);
135 newNetconfReplyTimeout = isNullOrEmpty(s) ?
136 netconfReplyTimeout : Integer.parseInt(s.trim());
137
138 s = get(properties, PROP_NETCONF_CONNECT_TIMEOUT);
139 newNetconfConnectTimeout = isNullOrEmpty(s) ?
140 netconfConnectTimeout : Integer.parseInt(s.trim());
141
142 } catch (NumberFormatException e) {
143 log.warn("Component configuration had invalid value", e);
144 return;
145 }
146
147 if (newNetconfConnectTimeout < 0) {
148 log.warn("netconfConnectTimeout is invalid - less than 0");
149 return;
150 } else if (newNetconfReplyTimeout <= 0) {
151 log.warn("netconfReplyTimeout is invalid - 0 or less.");
152 return;
153 }
154
155 netconfReplyTimeout = newNetconfReplyTimeout;
156 netconfConnectTimeout = newNetconfConnectTimeout;
157 log.info("Settings: {} = {}, {} = {}",
158 PROP_NETCONF_REPLY_TIMEOUT, netconfReplyTimeout, PROP_NETCONF_CONNECT_TIMEOUT, netconfConnectTimeout);
159 }
160
161 @Override
162 public void addDeviceListener(NetconfDeviceListener listener) {
163 if (!netconfDeviceListeners.contains(listener)) {
164 netconfDeviceListeners.add(listener);
165 }
166 }
167
168 @Override
169 public void removeDeviceListener(NetconfDeviceListener listener) {
170 netconfDeviceListeners.remove(listener);
171 }
172
173 @Override
174 public NetconfDevice getNetconfDevice(DeviceId deviceInfo) {
175 return netconfDeviceMap.get(deviceInfo);
176 }
177
178 @Override
179 public NetconfDevice getNetconfDevice(IpAddress ip, int port) {
180 for (DeviceId info : netconfDeviceMap.keySet()) {
181 if (info.uri().getSchemeSpecificPart().equals(ip.toString() + ":" + port)) {
182 return netconfDeviceMap.get(info);
183 }
184 }
185 return null;
186 }
187
188 @Override
189 public NetconfDevice connectDevice(DeviceId deviceId) throws NetconfException {
190 if (netconfDeviceMap.containsKey(deviceId)) {
191 log.debug("Device {} is already present", deviceId);
192 return netconfDeviceMap.get(deviceId);
193 } else {
194 log.debug("Creating NETCONF device {}", deviceId);
195 Device device = deviceService.getDevice(deviceId);
196 String ip;
197 int port;
198 if (device != null) {
199 ip = device.annotations().value("ipaddress");
200 port = Integer.parseInt(device.annotations().value("port"));
201 } else {
202 String[] info = deviceId.toString().split(":");
203 if (info.length == 3) {
204 ip = info[1];
205 port = Integer.parseInt(info[2]);
206 } else {
207 ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
208 && !el.equals(info[info.length - 1]))
209 .reduce((t, u) -> t + ":" + u)
210 .get();
211 log.debug("ip v6 {}", ip);
212 port = Integer.parseInt(info[info.length - 1]);
213 }
214 }
215 try {
216 DeviceKey deviceKey = deviceKeyService.getDeviceKey(
217 DeviceKeyId.deviceKeyId(deviceId.toString()));
218 NetconfDeviceInfo deviceInfo = null;
219 if (deviceKey.type() == DeviceKey.Type.USERNAME_PASSWORD) {
220 UsernamePassword usernamepasswd = deviceKey.asUsernamePassword();
221
222 deviceInfo = new NetconfDeviceInfo(usernamepasswd.username(),
223 usernamepasswd.password(),
224 IpAddress.valueOf(ip),
225 port);
226
227 } else if (deviceKey.type() == DeviceKey.Type.SSL_KEY) {
228 String username = deviceKey.annotations().value(AnnotationKeys.USERNAME);
229 String password = deviceKey.annotations().value(AnnotationKeys.PASSWORD);
230 String sshkey = deviceKey.annotations().value(AnnotationKeys.SSHKEY);
231
232 deviceInfo = new NetconfDeviceInfo(username,
233 password,
234 IpAddress.valueOf(ip),
235 port,
236 sshkey);
237 } else {
238 log.error("Unknown device key for device {}", deviceId);
239 }
240 NetconfDevice netconfDevicedevice = createDevice(deviceInfo);
241 netconfDevicedevice.getSession().addDeviceOutputListener(downListener);
242 return netconfDevicedevice;
243 } catch (NullPointerException e) {
244 throw new NetconfException("No Device Key for device " + deviceId, e);
245 }
246 }
247 }
248
249 @Override
250 public void disconnectDevice(DeviceId deviceId, boolean remove) {
251 if (!netconfDeviceMap.containsKey(deviceId)) {
252 log.warn("Device {} is not present", deviceId);
253 } else {
254 stopDevice(deviceId, remove);
255 }
256 }
257
258 private void stopDevice(DeviceId deviceId, boolean remove) {
259 netconfDeviceMap.get(deviceId).disconnect();
260 netconfDeviceMap.remove(deviceId);
261 if (remove) {
262 for (NetconfDeviceListener l : netconfDeviceListeners) {
263 l.deviceRemoved(deviceId);
264 }
265 }
266 }
267
268 @Override
269 public void removeDevice(DeviceId deviceId) {
270 if (!netconfDeviceMap.containsKey(deviceId)) {
271 log.warn("Device {} is not present", deviceId);
272 for (NetconfDeviceListener l : netconfDeviceListeners) {
273 l.deviceRemoved(deviceId);
274 }
275 } else {
276 netconfDeviceMap.remove(deviceId);
277 for (NetconfDeviceListener l : netconfDeviceListeners) {
278 l.deviceRemoved(deviceId);
279 }
280 }
281 }
282
283 private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
284 NetconfDevice netconfDevice = deviceFactory.createNetconfDevice(deviceInfo);
285 netconfDeviceMap.put(deviceInfo.getDeviceId(), netconfDevice);
286 for (NetconfDeviceListener l : netconfDeviceListeners) {
287 l.deviceAdded(deviceInfo.getDeviceId());
288 }
289 return netconfDevice;
290 }
291
292
293 @Override
294 public Map<DeviceId, NetconfDevice> getDevicesMap() {
295 return netconfDeviceMap;
296 }
297
298 @Override
299 public Set<DeviceId> getNetconfDevices() {
300 return netconfDeviceMap.keySet();
301 }
302
303
304 //Device factory for the specific NetconfDeviceImpl
305 private class DefaultNetconfDeviceFactory implements NetconfDeviceFactory {
306
307 @Override
308 public NetconfDevice createNetconfDevice(NetconfDeviceInfo netconfDeviceInfo) throws NetconfException {
309 return new DefaultNetconfDevice(netconfDeviceInfo);
310 }
311 }
312
313 //Listener for closed session with devices, gets triggered whe devices goes down
314 // or sends the endpattern ]]>]]>
315 private class DeviceDownEventListener implements NetconfDeviceOutputEventListener {
316
317 @Override
318 public void event(NetconfDeviceOutputEvent event) {
319 DeviceId did = event.getDeviceInfo().getDeviceId();
320 if (event.type().equals(NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED)) {
321 removeDevice(did);
322 } else if (event.type().equals(NetconfDeviceOutputEvent.Type.SESSION_CLOSED)) {
323 log.info("Trying to reestablish connection with device {}", did);
324 executor.execute(() -> {
325 try {
326 netconfDeviceMap.get(did).getSession().checkAndReestablish();
327 log.info("Connection with device {} was reestablished", did);
328 } catch (NetconfException e) {
329 log.error("The SSH connection with device {} couldn't be " +
330 "reestablished due to {}. " +
331 "Marking the device as unreachable", e.getMessage());
332 log.debug("Complete exception: ", e);
333 removeDevice(did);
334 }
335 });
336 }
337 }
338
339 @Override
340 public boolean isRelevant(NetconfDeviceOutputEvent event) {
341 return getDevicesMap().containsKey(event.getDeviceInfo().getDeviceId());
342 }
343 }
344}