blob: 5a78260dad715b34ee954d94d7e6e042cd73c628 [file] [log] [blame]
kmcpeakeb172d5f2015-12-10 11:30:43 +00001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
kmcpeakeb172d5f2015-12-10 11:30:43 +00003 *
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 */
16package org.onosproject.provider.snmp.device.impl;
17
Andrea Campanella59b549d2017-04-14 21:58:16 +020018import com.google.common.collect.ImmutableList;
kmcpeakeb172d5f2015-12-10 11:30:43 +000019import 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;
kmcpeakeb172d5f2015-12-10 11:30:43 +000023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.ChassisId;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070026import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
Ray Milkey6c013742017-08-15 10:16:43 -070028import org.onosproject.net.config.ConfigException;
Marc De Leenheerc662d322016-02-18 16:05:10 -080029import org.onosproject.net.AnnotationKeys;
30import org.onosproject.net.DefaultAnnotations;
kmcpeakeb172d5f2015-12-10 11:30:43 +000031import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070034import org.onosproject.net.PortNumber;
Marc De Leenheerc662d322016-02-18 16:05:10 -080035import org.onosproject.net.SparseAnnotations;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070036import org.onosproject.net.config.ConfigFactory;
37import org.onosproject.net.config.NetworkConfigEvent;
38import org.onosproject.net.config.NetworkConfigListener;
39import org.onosproject.net.config.NetworkConfigRegistry;
Andrea Campanella59b549d2017-04-14 21:58:16 +020040import org.onosproject.net.config.basics.SubjectFactories;
kmcpeakeb172d5f2015-12-10 11:30:43 +000041import org.onosproject.net.device.DefaultDeviceDescription;
42import org.onosproject.net.device.DeviceDescription;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070043import org.onosproject.net.device.DeviceDescriptionDiscovery;
kmcpeakeb172d5f2015-12-10 11:30:43 +000044import org.onosproject.net.device.DeviceProvider;
45import org.onosproject.net.device.DeviceProviderRegistry;
46import org.onosproject.net.device.DeviceProviderService;
47import org.onosproject.net.device.DeviceService;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070048import org.onosproject.net.device.DeviceStore;
kmcpeakeb172d5f2015-12-10 11:30:43 +000049import org.onosproject.net.provider.AbstractProvider;
50import org.onosproject.net.provider.ProviderId;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070051import org.onosproject.snmp.SnmpController;
52import org.onosproject.snmp.SnmpDevice;
53import org.onosproject.snmp.ctl.DefaultSnmpDevice;
kmcpeakeb172d5f2015-12-10 11:30:43 +000054import org.osgi.service.component.ComponentContext;
55import org.slf4j.Logger;
56
Andrea Campanella59b549d2017-04-14 21:58:16 +020057import java.util.List;
58import java.util.Set;
Jonathan Hart51539b82015-10-29 09:53:04 -070059import java.util.concurrent.ExecutorService;
60import java.util.concurrent.Executors;
61import java.util.concurrent.TimeUnit;
62
Jonathan Hart51539b82015-10-29 09:53:04 -070063import static org.onlab.util.Tools.groupedThreads;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070064import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Jonathan Hart51539b82015-10-29 09:53:04 -070065import static org.slf4j.LoggerFactory.getLogger;
66
kmcpeakeb172d5f2015-12-10 11:30:43 +000067/**
68 * Provider which will try to fetch the details of SNMP devices from the core and run a capability discovery on each of
69 * the device.
70 */
71@Component(immediate = true)
72public class SnmpDeviceProvider extends AbstractProvider
73 implements DeviceProvider {
74
75 private final Logger log = getLogger(SnmpDeviceProvider.class);
76
77 private static final String UNKNOWN = "unknown";
Andrea Campanellac2d754b2016-03-29 17:51:07 -070078 private static final String APP_NAME = "org.onosproject.snmp";
Andrea Campanella59b549d2017-04-14 21:58:16 +020079 protected static final String SCHEME = "snmp";
kmcpeakeb172d5f2015-12-10 11:30:43 +000080
kmcpeakeb172d5f2015-12-10 11:30:43 +000081 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070082 protected SnmpController controller;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
kmcpeakeb172d5f2015-12-10 11:30:43 +000085 protected DeviceProviderRegistry providerRegistry;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceService deviceService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070091 protected DeviceStore deviceStore;
kmcpeakeb172d5f2015-12-10 11:30:43 +000092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070094 protected CoreService coreService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000095
Andrea Campanellac2d754b2016-03-29 17:51:07 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected NetworkConfigRegistry netCfgService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000098
Andrea Campanella58454b92016-04-01 15:19:00 -070099 protected DeviceProviderService providerService;
100
101 protected ApplicationId appId;
102
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700103 private final ExecutorService deviceBuilderExecutor = Executors
104 .newFixedThreadPool(5, groupedThreads("onos/snmp", "device-creator", log));
kmcpeakeb172d5f2015-12-10 11:30:43 +0000105
Andrea Campanella58454b92016-04-01 15:19:00 -0700106 protected final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000107
kmcpeakeb172d5f2015-12-10 11:30:43 +0000108
Andrea Campanella59b549d2017-04-14 21:58:16 +0200109 protected final List<ConfigFactory> factories = ImmutableList.of(
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700110 new ConfigFactory<ApplicationId, SnmpProviderConfig>(APP_SUBJECT_FACTORY,
111 SnmpProviderConfig.class,
Palash Kalac3ffad92017-06-09 21:18:19 +0900112 "snmp_devices",
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700113 true) {
114 @Override
115 public SnmpProviderConfig createConfig() {
116 return new SnmpProviderConfig();
117 }
Andrea Campanella59b549d2017-04-14 21:58:16 +0200118 },
119 new ConfigFactory<DeviceId, SnmpDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
120 SnmpDeviceConfig.class,
121 SCHEME) {
122 @Override
123 public SnmpDeviceConfig createConfig() {
124 return new SnmpDeviceConfig();
125 }
126 });
kmcpeakeb172d5f2015-12-10 11:30:43 +0000127
kmcpeakeb172d5f2015-12-10 11:30:43 +0000128
129 /**
130 * Creates a provider with the supplier identifier.
131 */
132 public SnmpDeviceProvider() {
133 super(new ProviderId("snmp", "org.onosproject.provider.device"));
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700134 //FIXME multiple type of SNMP sessions
kmcpeakeb172d5f2015-12-10 11:30:43 +0000135 }
136
137 @Activate
138 public void activate(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700139
kmcpeakeb172d5f2015-12-10 11:30:43 +0000140 providerService = providerRegistry.register(this);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700141 appId = coreService.registerApplication(APP_NAME);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200142 factories.forEach(netCfgService::registerConfigFactory);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700143 netCfgService.addListener(cfgLister);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200144 connectDevices();
145 addOrRemoveDevicesConfig();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000146 modified(context);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700147 log.info("Started");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000148 }
149
150 @Deactivate
151 public void deactivate(ComponentContext context) {
152
kmcpeakeb172d5f2015-12-10 11:30:43 +0000153 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700154 controller.getDevices().forEach(device -> {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700155 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
156 });
157 deviceBuilderExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000158 } catch (InterruptedException e) {
Ray Milkey5c7d4882018-02-05 14:50:39 -0800159 Thread.currentThread().interrupt();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000160 log.error("Device builder did not terminate");
161 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700162 deviceBuilderExecutor.shutdownNow();
Andrea Campanella59b549d2017-04-14 21:58:16 +0200163 factories.forEach(netCfgService::unregisterConfigFactory);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700164 netCfgService.removeListener(cfgLister);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000165 providerRegistry.unregister(this);
166 providerService = null;
167 log.info("Stopped");
168 }
169
170 @Modified
171 public void modified(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700172 log.info("Modified");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000173 }
174
Andrea Campanella59b549d2017-04-14 21:58:16 +0200175 //Old method to register devices provided via net-cfg under apps/snmp/ tree
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700176 private void addOrRemoveDevicesConfig() {
177 SnmpProviderConfig cfg = netCfgService.getConfig(appId, SnmpProviderConfig.class);
178 if (cfg != null) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000179 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700180 cfg.getDevicesInfo().forEach(info -> {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200181 buildDevice(new DefaultSnmpDevice(info.ip().toString(),
182 info.port(), info.username(),
183 info.password()));
184
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700185 });
186 } catch (ConfigException e) {
187 log.error("Cannot read config error " + e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000188 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000189 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700190 }
191
Andrea Campanella59b549d2017-04-14 21:58:16 +0200192 //Method to register devices provided via net-cfg under devices/ tree
193 private void connectDevices() {
194 Set<DeviceId> deviceSubjects =
195 netCfgService.getSubjects(DeviceId.class, SnmpDeviceConfig.class);
196 deviceSubjects.forEach(deviceId -> {
197 SnmpDeviceConfig config =
198 netCfgService.getConfig(deviceId, SnmpDeviceConfig.class);
199 buildDevice(new DefaultSnmpDevice(config.ip().toString(),
200 config.port(), config.username(), config.password()));
201 });
202 }
203
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700204 private void buildDevice(SnmpDevice device) {
205 if (device != null) {
206 log.debug("Device Detail:host={}, port={}, state={}",
207 device.getSnmpHost(),
208 device.getSnmpPort(),
209 device.isReachable());
210 if (device.isReachable()) {
211 deviceBuilderExecutor.execute(new DeviceFactory(device, true));
212 } else {
213 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
214 }
215 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000216 }
217
218 @Override
219 public void triggerProbe(DeviceId deviceId) {
220 // TODO SNMP devices should be polled at scheduled intervals to retrieve their
221 // reachability status and other details e.g.swVersion, serialNumber,chassis,
222 }
223
224 @Override
225 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700226 // TODO Implement Masterhsip Service
kmcpeakeb172d5f2015-12-10 11:30:43 +0000227 }
228
229 @Override
230 public boolean isReachable(DeviceId deviceId) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700231 SnmpDevice snmpDevice = controller.getDevice(deviceId);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000232 if (snmpDevice == null) {
233 log.warn("BAD REQUEST: the requested device id: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700234 + deviceId.toString()
235 + " is not associated to any SNMP Device");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000236 return false;
237 }
238 return snmpDevice.isReachable();
239 }
240
241 /**
242 * This class is intended to add or remove Configured SNMP Devices. Functionality relies on 'createFlag' and
243 * 'SnmpDevice' content. The functionality runs as a thread and depending on the 'createFlag' value it will create
244 * or remove Device entry from the core.
245 */
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700246 //FIXME consider rework.
247 private class DeviceFactory implements Runnable {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000248
249 private SnmpDevice device;
250 private boolean createFlag;
251
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700252 public DeviceFactory(SnmpDevice device, boolean createFlag) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000253 this.device = device;
254 this.createFlag = createFlag;
255 }
256
257 @Override
258 public void run() {
259 if (createFlag) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700260 log.debug("Trying to create Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000261 advertiseDevices();
262 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700263 log.debug("Trying to remove Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000264 removeDevices();
265 }
266 }
267
268 /**
269 * For each SNMP Device, remove the entry from the device store.
270 */
271 private void removeDevices() {
272 if (device == null) {
273 log.warn("The Request SNMP Device is null, cannot proceed further");
274 return;
275 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700276 DeviceId did = device.deviceId();
277 if (controller.getDevice(did) == null) {
278 log.error("BAD Request: 'Currently device is not discovered, "
279 + "so cannot remove/disconnect the device: "
280 + device.deviceInfo() + "'");
281 return;
kmcpeakeb172d5f2015-12-10 11:30:43 +0000282 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700283 providerService.deviceDisconnected(did);
284 device.disconnect();
285 controller.removeDevice(did);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000286 }
287
288 /**
289 * Initialize SNMP Device object, and notify core saying device connected.
290 */
291 private void advertiseDevices() {
292 try {
293 if (device == null) {
294 log.warn("The Request SNMP Device is null, cannot proceed further");
295 return;
296 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700297 DeviceId did = device.deviceId();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000298 ChassisId cid = new ChassisId();
299
Marc De Leenheerc662d322016-02-18 16:05:10 -0800300 SparseAnnotations annotations = DefaultAnnotations.builder()
301 .set(AnnotationKeys.PROTOCOL, SCHEME.toUpperCase())
302 .build();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000303
304 DeviceDescription desc = new DefaultDeviceDescription(
Marc De Leenheerc662d322016-02-18 16:05:10 -0800305 did.uri(), Device.Type.OTHER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid, annotations);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000306
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700307 log.debug("Persisting Device " + did.uri().toString());
kmcpeakeb172d5f2015-12-10 11:30:43 +0000308
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700309 controller.addDevice(did, device);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000310 providerService.deviceConnected(did, desc);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700311 log.info("Added device to ONOS core. Device Info: "
312 + device.deviceInfo() + " " + did.uri().toString());
313 //FIXME this description will be populated only if driver is pushed from outside
Frank Wangd8ab0962017-08-11 11:09:30 +0800314 // because otherwise default driver is used
Marc De Leenheerc662d322016-02-18 16:05:10 -0800315 Device d = deviceService.getDevice(did);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700316 if (d.is(DeviceDescriptionDiscovery.class)) {
317 DeviceDescriptionDiscovery descriptionDiscovery = d.as(DeviceDescriptionDiscovery.class);
318 DeviceDescription description = descriptionDiscovery.discoverDeviceDetails();
Andrea Campanella6c71a052016-04-22 11:56:31 -0700319 if (description != null) {
320 deviceStore.createOrUpdateDevice(
321 new ProviderId("snmp", "org.onosproject.provider.device"),
322 did, description);
323 } else {
324 log.info("No other description given for device {}", d.id());
325 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700326 providerService.updatePorts(did, descriptionDiscovery.discoverPortDetails());
Marc De Leenheerc662d322016-02-18 16:05:10 -0800327 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700328 log.warn("No populate description and ports behaviour for device {}", did);
Marc De Leenheerc662d322016-02-18 16:05:10 -0800329 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000330 } catch (Exception e) {
331 log.error("Error while initializing session for the device: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700332 + (device != null ? device.deviceInfo() : null), e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000333 }
334 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000335 }
336
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700337 private class InternalNetworkConfigListener implements NetworkConfigListener {
338
339
340 @Override
341 public void event(NetworkConfigEvent event) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200342 if (event.configClass().equals(SnmpDeviceConfig.class)) {
343 connectDevices();
344 } else {
345 log.warn("Injecting device via this Json is deprecated, " +
346 "please put configuration under devices/");
347 addOrRemoveDevicesConfig();
348 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700349 }
350
351 @Override
352 public boolean isRelevant(NetworkConfigEvent event) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200353 return (event.configClass().equals(SnmpDeviceConfig.class) ||
354 event.configClass().equals(SnmpProviderConfig.class)) &&
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700355 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
356 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
357 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000358 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700359
360 @Override
361 public void changePortState(DeviceId deviceId, PortNumber portNumber,
362 boolean enable) {
363 // TODO if required
364 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000365}