blob: 4d2c658ec45934701baa9adacd46f2595d8898d7 [file] [log] [blame]
kmcpeakeb172d5f2015-12-10 11:30:43 +00001/*
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 */
16package org.onosproject.provider.snmp.alarm.impl;
17
18import com.btisystems.pronx.ems.core.snmp.DefaultSnmpConfigurationFactory;
19import com.btisystems.pronx.ems.core.snmp.ISnmpConfiguration;
20import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
21import com.btisystems.pronx.ems.core.snmp.ISnmpSessionFactory;
22import com.btisystems.pronx.ems.core.snmp.SnmpSessionFactory;
23import com.btisystems.pronx.ems.core.snmp.V2cSnmpConfiguration;
24import static com.google.common.base.Preconditions.checkNotNull;
25import com.google.common.collect.Sets;
26import java.io.IOException;
27import static org.slf4j.LoggerFactory.getLogger;
28
29import java.util.Collection;
30import java.util.HashMap;
31import java.util.HashSet;
32import java.util.Map;
33import java.util.Set;
34import java.util.concurrent.ExecutorService;
35import java.util.concurrent.Executors;
36
37import org.apache.felix.scr.annotations.Activate;
38import org.apache.felix.scr.annotations.Component;
39import org.apache.felix.scr.annotations.Deactivate;
40import org.apache.felix.scr.annotations.Modified;
41import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
42import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEvent;
43import org.onosproject.incubator.net.faultmanagement.alarm.AlarmListener;
44import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider;
45
46import org.onosproject.net.DeviceId;
47import org.onosproject.net.provider.AbstractProvider;
48import org.onosproject.net.provider.ProviderId;
49import org.osgi.service.component.ComponentContext;
50import org.slf4j.Logger;
51import org.apache.felix.scr.annotations.Reference;
52import org.apache.felix.scr.annotations.ReferenceCardinality;
53import static org.onlab.util.Tools.groupedThreads;
54import org.onosproject.core.ApplicationId;
55import org.onosproject.core.CoreService;
56import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
57import org.onosproject.net.device.DeviceEvent;
58import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
59import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
60import org.onosproject.net.device.DeviceListener;
61import org.onosproject.net.device.DeviceService;
62
63/**
64 * SNMP alarms provider.
65 */
66@Component(immediate = true)
67public class SnmpAlarmProviderService extends AbstractProvider implements AlarmProvider {
68
69 private final Logger log = getLogger(getClass());
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected DeviceService deviceService;
76
77 private ApplicationId appId;
78
79 private final ISnmpSessionFactory sessionFactory;
80
81 // TODO convert to standard ONOS listener service approach ?
82 protected Set<AlarmListener> alarmEventListener = Sets.newHashSet();
83
84 private ExecutorService eventHandlingExecutor;
85
86 // TODO Could be replaced with a service lookup, and bundles per device variant.
87 Map<String, SnmpDeviceAlarmProvider> providers = new HashMap<>();
88
89 public SnmpAlarmProviderService() {
90 super(new ProviderId("snmp", "org.onosproject.provider.alarm"));
91 sessionFactory = new SnmpSessionFactory(
92 new DefaultSnmpConfigurationFactory(new V2cSnmpConfiguration()));
93 providers.put("1.3.6.1.4.1.18070.2.2", new Bti7000SnmpAlarmProvider());
94 providers.put("1.3.6.1.4.1.20408", new NetSnmpAlarmProvider());
95 }
96
97 @Activate
98 public void activate(ComponentContext context) {
99 appId = coreService.registerApplication("org.onosproject.snmp");
100 eventHandlingExecutor = Executors.newSingleThreadExecutor(
101 groupedThreads("onos/alarms", "event-handler"));
102 deviceService.addListener(new InternalDeviceListener());
103 log.info("activated SNMP provider with appId = {} and context props {}", appId, context.getProperties());
104 modified(context);
105
106 log.info("Started");
107 }
108
109 @Deactivate
110 public void deactivate() {
111 log.info("deactivate SNMP provider {}", appId);
112 }
113
114 @Modified
115 public void modified(ComponentContext context) {
116 log.info("modified {}", context);
117
118 if (context == null) {
119 log.info("No configuration file");
120 }
121
122 }
123
124 @Override
125 public void triggerProbe(DeviceId deviceId) {
126 log.info("SNMP walk request for alarms at deviceId={}", deviceId);
127 if (!isSnmpDevice(deviceId)) {
128 log.info("Ignore non-snmp device!");
129 return;
130 }
131 String[] deviceComponents = deviceId.toString().split(":");
132 Set<Alarm> alarms = new HashSet<>(Sets.newHashSet());
133
134 if (deviceComponents.length > 1) {
135 String ipAddress = deviceComponents[1];
136 String port = deviceComponents[2];
137 ISnmpConfiguration config = new V2cSnmpConfiguration();
138 config.setPort(Integer.parseInt(port));
139
140 try (ISnmpSession session = getSessionFactory().createSession(config, ipAddress)) {
141 // Each session will be auto-closed.
142 String deviceOID = session.identifyDevice();
143 alarms.addAll(getAlarmsForDevice(deviceOID, session, deviceId));
144 log.info("SNMP walk completed ok for deviceId={}", deviceId);
145 } catch (IOException | RuntimeException ex) {
146 log.error("Failed to walk device.", ex.getMessage());
147 log.debug("Detailed problem was ", ex);
148 alarms.add(
149 buildWalkFailedAlarm(deviceId)
150 );
151 }
152 }
153
154 AlarmEvent alarmEvent = new AlarmEvent(alarms, deviceId);
155
156 alarmEventListener.stream().forEach((listener) -> {
157 listener.event(alarmEvent);
158 log.info("Successfully event with discovered alarms for deviceId={} to {}", deviceId, listener);
159 });
160
161 }
162
163 private static DefaultAlarm buildWalkFailedAlarm(DeviceId deviceId) {
164 return new DefaultAlarm.Builder(
165 deviceId, "SNMP alarm retrieval failed",
166 Alarm.SeverityLevel.CRITICAL,
167 System.currentTimeMillis()).build();
168 }
169
170 protected ISnmpSessionFactory getSessionFactory() {
171 return sessionFactory;
172 }
173
174 private Collection<Alarm> getAlarmsForDevice(String deviceOID, ISnmpSession session,
175 DeviceId deviceID) throws IOException {
176 Collection<Alarm> alarms = new HashSet<>();
177 if (providers.containsKey(deviceOID)) {
178 alarms.addAll(providers.get(deviceOID).getAlarms(session, deviceID));
179 }
180 return alarms;
181 }
182
183 @Override
184 public void addAlarmListener(AlarmListener listener) {
185 alarmEventListener.add(checkNotNull(listener, "Listener cannot be null"));
186 }
187
188 @Override
189 public void removeAlarmListener(AlarmListener listener) {
190 alarmEventListener.remove(checkNotNull(listener, "Listener cannot be null"));
191 }
192
193 /**
194 * Internal listener for device service events.
195 */
196 private class InternalDeviceListener implements DeviceListener {
197
198 @Override
199 public void event(DeviceEvent event) {
200 log.info("InternalDeviceListener has got event from device-service{} with ", event);
201 eventHandlingExecutor.execute(() -> {
202 try {
203 DeviceId deviceId = event.subject().id();
204 log.info("From device {}", deviceId);
205 if (!isSnmpDevice(deviceId)) {
206 log.info("Ignore non-snmp device event for {}", deviceId);
207 return;
208 }
209
210 switch (event.type()) {
211 case DEVICE_ADDED:
212 case DEVICE_UPDATED:
213 case DEVICE_AVAILABILITY_CHANGED:
214 if (deviceService.isAvailable(event.subject().id())) {
215 triggerProbe(deviceId);
216 }
217 break;
218 case DEVICE_REMOVED:
219 case DEVICE_SUSPENDED:
220 default:
221 // Could potentially remove all alarms when eg DEVICE_REMOVED or DEVICE_SUSPENDED
222 // however for now ignore and fall through
223 break;
224 }
225 } catch (Exception e) {
226 log.warn("Failed to process {}", event, e);
227 }
228 });
229 }
230
231 }
232
233 private static boolean isSnmpDevice(DeviceId deviceId) {
234 return deviceId.uri().getScheme().equalsIgnoreCase("snmp");
235 }
236}