kmcpeake
Committed by Gerrit Code Review

[ONOS-3203] End-to-end demo of Fault Management via SNMP.

This adds SNMP device-discovery, and a Fault Management app which makes alarms available to users via REST/GUI/CLI interfaces.
There is still code cleanup that could be done, but aim of this commit is an end-to-end proof of concept.

To demonstrate :

1) /opt/onos/bin/onos-service
onos> app activate org.onosproject.snmp
onos> app activate org.onosproject.faultmanagement

2) SNMP devices are seeded via config file. The default seed file contains connection details for devices (SNMP agents) available via internet  e.g. demo.snmplabs.com
cp /opt/onos/apache-karaf-3.0.3/etc/samples/org.onosproject.provider.snmp.device.impl.SnmpDeviceProvider.cfg   /opt/onos/apache-karaf-3.0.3/etc/

3) ONOS will poll these SNMP devices and store their alarms.

4) You can now manipulate the alarms via REST  e.g. http://<onos>:8181/onos/v1/fm/alarms , via CLI  via various "alarm-*” commands or in UI with an Alarms Overlay.

More info at https://wiki.onosproject.org/display/ONOS/Fault+Management

15/Dec/15: Updated regarding review comments from Thomas Vachuska.
17/Dec/15: Updated coreService.registerApplication(name) as per https://gerrit.onosproject.org/#/c/6878/

Change-Id: I886f8511f178dc4600ab96e5ff10cc90329cabec
Showing 76 changed files with 4194 additions and 369 deletions
...@@ -21,4 +21,6 @@ ...@@ -21,4 +21,6 @@
21 21
22 <artifact>mvn:${project.groupId}/onos-app-fm-mgr/${project.version}</artifact> 22 <artifact>mvn:${project.groupId}/onos-app-fm-mgr/${project.version}</artifact>
23 <artifact>mvn:${project.groupId}/onos-app-fm-web/${project.version}</artifact> 23 <artifact>mvn:${project.groupId}/onos-app-fm-web/${project.version}</artifact>
24 + <artifact>mvn:${project.groupId}/onos-app-fm-gui/${project.version}</artifact>
25 + <artifact>mvn:${project.groupId}/onos-app-fm-cli/${project.version}</artifact>
24 </app> 26 </app>
......
...@@ -21,5 +21,7 @@ ...@@ -21,5 +21,7 @@
21 <feature>onos-drivers</feature> 21 <feature>onos-drivers</feature>
22 <bundle>mvn:${project.groupId}/onos-app-fm-mgr/${project.version}</bundle> 22 <bundle>mvn:${project.groupId}/onos-app-fm-mgr/${project.version}</bundle>
23 <bundle>mvn:${project.groupId}/onos-app-fm-web/${project.version}</bundle> 23 <bundle>mvn:${project.groupId}/onos-app-fm-web/${project.version}</bundle>
24 + <bundle>mvn:${project.groupId}/onos-app-fm-gui/${project.version}</bundle>
25 + <bundle>mvn:${project.groupId}/onos-app-fm-cli/${project.version}</bundle>
24 </feature> 26 </feature>
25 </features> 27 </features>
......
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- 2 <!--
3 - ~ Copyright 2015 Open Networking Laboratory 3 +~ Copyright 2015 Open Networking Laboratory
4 - ~ 4 +~
5 - ~ Licensed under the Apache License, Version 2.0 (the "License"); 5 +~ Licensed under the Apache License, Version 2.0 (the "License");
6 - ~ you may not use this file except in compliance with the License. 6 +~ you may not use this file except in compliance with the License.
7 - ~ You may obtain a copy of the License at 7 +~ You may obtain a copy of the License at
8 - ~ 8 +~
9 - ~ http://www.apache.org/licenses/LICENSE-2.0 9 +~ http://www.apache.org/licenses/LICENSE-2.0
10 - ~ 10 +~
11 - ~ Unless required by applicable law or agreed to in writing, software 11 +~ Unless required by applicable law or agreed to in writing, software
12 - ~ distributed under the License is distributed on an "AS IS" BASIS, 12 +~ distributed under the License is distributed on an "AS IS" BASIS,
13 - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 - ~ See the License for the specific language governing permissions and 14 +~ See the License for the specific language governing permissions and
15 - ~ limitations under the License. 15 +~ limitations under the License.
16 - --> 16 +-->
17 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 17 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 18 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
19 <modelVersion>4.0.0</modelVersion> 19 <modelVersion>4.0.0</modelVersion>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
28 <artifactId>onos-app-fm-onosfw</artifactId> 28 <artifactId>onos-app-fm-onosfw</artifactId>
29 <packaging>pom</packaging> 29 <packaging>pom</packaging>
30 30
31 - <description>ONOS framework applications</description> 31 + <description>ONOS fault management application</description>
32 32
33 <dependencies> 33 <dependencies>
34 <dependency> 34 <dependency>
...@@ -41,6 +41,15 @@ ...@@ -41,6 +41,15 @@
41 <artifactId>onos-app-fm-mgr</artifactId> 41 <artifactId>onos-app-fm-mgr</artifactId>
42 <version>${project.version}</version> 42 <version>${project.version}</version>
43 </dependency> 43 </dependency>
44 + <dependency>
45 + <groupId>org.onosproject</groupId>
46 + <artifactId>onos-app-fm-gui</artifactId>
47 + <version>${project.version}</version>
48 + </dependency>
49 + <dependency>
50 + <groupId>org.onosproject</groupId>
51 + <artifactId>onos-app-fm-cli</artifactId>
52 + <version>${project.version}</version>
53 + </dependency>
44 </dependencies> 54 </dependencies>
45 -
46 </project> 55 </project>
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 +~ Copyright 2015 Open Networking Laboratory
4 +~
5 +~ Licensed under the Apache License, Version 2.0 (the "License");
6 +~ you may not use this file except in compliance with the License.
7 +~ You may obtain a copy of the License at
8 +~
9 +~ http://www.apache.org/licenses/LICENSE-2.0
10 +~
11 +~ Unless required by applicable law or agreed to in writing, software
12 +~ distributed under the License is distributed on an "AS IS" BASIS,
13 +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 +~ See the License for the specific language governing permissions and
15 +~ limitations under the License.
16 +-->
17 +<project
18 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
19 + xmlns="http://maven.apache.org/POM/4.0.0"
20 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
21 +
22 + <modelVersion>4.0.0</modelVersion>
23 +
24 + <parent>
25 + <groupId>org.onosproject</groupId>
26 + <artifactId>onos-app-fm</artifactId>
27 + <version>1.4.0-SNAPSHOT</version>
28 + <relativePath>../pom.xml</relativePath>
29 + </parent>
30 +
31 + <artifactId>onos-app-fm-cli</artifactId>
32 + <packaging>bundle</packaging>
33 + <dependencies>
34 + <dependency>
35 + <groupId>org.onosproject</groupId>
36 + <artifactId>onlab-osgi</artifactId>
37 + <version>${project.version}</version>
38 + </dependency>
39 +
40 + <dependency>
41 + <groupId>org.onosproject</groupId>
42 + <artifactId>onlab-junit</artifactId>
43 + <scope>test</scope>
44 + </dependency>
45 +
46 + <dependency>
47 + <groupId>org.apache.felix</groupId>
48 + <artifactId>org.apache.felix.scr.annotations</artifactId>
49 + <scope>provided</scope>
50 + </dependency>
51 + <dependency>
52 + <groupId>org.onosproject</groupId>
53 + <artifactId>onos-cli</artifactId>
54 + <version>${project.version}</version>
55 + </dependency>
56 + <dependency>
57 + <groupId>org.apache.karaf.shell</groupId>
58 + <artifactId>org.apache.karaf.shell.console</artifactId>
59 + </dependency>
60 + </dependencies>
61 +</project>
1 +/*
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 +package org.onosproject.faultmanagement.alarms.cli;
17 +
18 +import java.util.Set;
19 +import org.apache.commons.lang3.builder.ToStringBuilder;
20 +import org.apache.commons.lang3.builder.ToStringStyle;
21 +import org.apache.karaf.shell.commands.Command;
22 +import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
24 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
25 +
26 +/**
27 + * Lists active alarms across all devices.
28 + */
29 +@Command(scope = "onos", name = "alarm-list-active",
30 + description = "Lists all the ACTIVE alarms across all devices.")
31 +public class GetAllActiveAlarms extends AbstractShellCommand {
32 +
33 +
34 + @Override
35 + protected void execute() {
36 + printAlarms(AbstractShellCommand.get(AlarmService.class).getActiveAlarms());
37 + }
38 +
39 + void printAlarms(Set<Alarm> alarms) {
40 + alarms.stream().forEach((alarm) -> {
41 + print(ToStringBuilder.reflectionToString(alarm, ToStringStyle.SHORT_PREFIX_STYLE));
42 + });
43 + }
44 +}
1 +/*
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 +package org.onosproject.faultmanagement.alarms.cli;
17 +
18 +import java.util.Set;
19 +import org.apache.commons.lang3.builder.ToStringBuilder;
20 +import org.apache.commons.lang3.builder.ToStringStyle;
21 +import org.apache.karaf.shell.commands.Command;
22 +import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
24 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
25 +
26 +/**
27 + * Lists alarms across all devices.
28 + */
29 +@Command(scope = "onos", name = "alarm-list",
30 + description = "Lists active alarms across all devices.")
31 +public class GetAllAlarms extends AbstractShellCommand {
32 +
33 + @Override
34 + protected void execute() {
35 + printAlarms(AbstractShellCommand.get(AlarmService.class).getAlarms());
36 + }
37 +
38 + void printAlarms(Set<Alarm> alarms) {
39 + alarms.stream().forEach((alarm) -> {
40 + print(ToStringBuilder.reflectionToString(alarm, ToStringStyle.SHORT_PREFIX_STYLE));
41 + });
42 + }
43 +}
1 +/*
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 +package org.onosproject.faultmanagement.alarms.cli;
17 +
18 +import java.util.Map;
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onosproject.cli.AbstractShellCommand;
21 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
22 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
23 +
24 +/**
25 + * Lists alarm counts across all devices.
26 + */
27 +@Command(scope = "onos", name = "alarm-counts",
28 + description = "Lists alarm counts across all devices.")
29 +public class GetAllAlarmsCounts extends AbstractShellCommand {
30 +
31 + @Override
32 + protected void execute() {
33 + Map<Alarm.SeverityLevel, Long> alarmCounts
34 + = AbstractShellCommand.get(AlarmService.class).getAlarmCounts();
35 + printCounts(alarmCounts);
36 + }
37 +
38 + static void printCounts(Map<Alarm.SeverityLevel, Long> alarmCounts) {
39 + alarmCounts.entrySet().stream().forEach((countEntry) -> {
40 + System.out.println(String.format("%s, %d",
41 + countEntry.getKey(), countEntry.getValue()));
42 +
43 + });
44 + }
45 +}
1 +/*
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 +package org.onosproject.faultmanagement.alarms.cli;
17 +
18 +import java.util.Map;
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
23 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
24 +import org.onosproject.net.DeviceId;
25 +
26 +/**
27 + * Lists alarm counts across specified device.
28 + */
29 +@Command(scope = "onos", name = "alarm-counts-device",
30 + description = "Lists alarm counts across specified device.")
31 +public class GetDeviceAlarmsCounts extends AbstractShellCommand {
32 +
33 + @Argument(index = 0, name = "deviceId", description = "Device identity", required = true, multiValued = false)
34 + String deviceId = null;
35 +
36 + @Override
37 + protected void execute() {
38 + Map<Alarm.SeverityLevel, Long> alarmCounts = AbstractShellCommand.get(AlarmService.class).
39 + getAlarmCounts(DeviceId.deviceId(deviceId));
40 + // Deliberately using same formatting for both ...
41 + GetAllAlarmsCounts.printCounts(alarmCounts);
42 + }
43 +
44 +}
1 +/*
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 +
17 +/**
18 + * CLI implementation for alarms.
19 + */
20 +package org.onosproject.faultmanagement.alarms.cli;
1 +<!--
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 +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
17 +
18 + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
19 +
20 + <command>
21 + <action class="org.onosproject.faultmanagement.alarms.cli.GetAllActiveAlarms"/>
22 + </command>
23 + <command>
24 + <action class="org.onosproject.faultmanagement.alarms.cli.GetAllAlarms"/>
25 + </command>
26 + <command>
27 + <action class="org.onosproject.faultmanagement.alarms.cli.GetAllAlarmsCounts"/>
28 + </command>
29 + <command>
30 + <action class="org.onosproject.faultmanagement.alarms.cli.GetDeviceAlarmsCounts"/>
31 + <completers>
32 + <ref component-id="deviceIdCompleter"/>
33 + </completers>
34 + </command>
35 + </command-bundle>
36 +
37 +
38 + <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
39 +
40 +</blueprint>
1 +# Need to write unit tests but do so after there are other CLI tests to use as a template.
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 +~ Copyright 2015 Open Networking Laboratory
4 +~
5 +~ Licensed under the Apache License, Version 2.0 (the "License");
6 +~ you may not use this file except in compliance with the License.
7 +~ You may obtain a copy of the License at
8 +~
9 +~ http://www.apache.org/licenses/LICENSE-2.0
10 +~
11 +~ Unless required by applicable law or agreed to in writing, software
12 +~ distributed under the License is distributed on an "AS IS" BASIS,
13 +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 +~ See the License for the specific language governing permissions and
15 +~ limitations under the License.
16 +-->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
19 + <modelVersion>4.0.0</modelVersion>
20 +
21 +
22 + <parent>
23 + <groupId>org.onosproject</groupId>
24 + <artifactId>onos-app-fm</artifactId>
25 + <version>1.4.0-SNAPSHOT</version>
26 + <relativePath>../pom.xml</relativePath>
27 + </parent>
28 +
29 + <artifactId>onos-app-fm-gui</artifactId>
30 + <packaging>bundle</packaging>
31 +
32 + <dependencies>
33 + <dependency>
34 + <groupId>org.apache.karaf.shell</groupId>
35 + <artifactId>org.apache.karaf.shell.console</artifactId>
36 + <scope>compile</scope>
37 + </dependency>
38 +
39 + <dependency>
40 + <groupId>org.onosproject</groupId>
41 + <artifactId>onlab-osgi</artifactId>
42 + </dependency>
43 +
44 + <dependency>
45 + <groupId>org.onosproject</groupId>
46 + <artifactId>onlab-junit</artifactId>
47 + <scope>test</scope>
48 + </dependency>
49 +
50 +
51 + <dependency>
52 + <groupId>org.apache.felix</groupId>
53 + <artifactId>org.apache.felix.scr.annotations</artifactId>
54 + <scope>provided</scope>
55 + </dependency>
56 +
57 + <dependency>
58 + <groupId>org.onosproject</groupId>
59 + <artifactId>onos-cli</artifactId>
60 + <version>${project.version}</version>
61 + <type>jar</type>
62 + </dependency>
63 + </dependencies>
64 +
65 +</project>
1 +/*
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 +package org.onosproject.faultmanagement.alarms.gui;
17 +
18 +import java.util.Map;
19 +import java.util.Set;
20 +import org.onosproject.cli.AbstractShellCommand;
21 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
22 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
23 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
24 +import org.onosproject.net.DeviceId;
25 +
26 +/**
27 + *
28 + * Utility for invoking on alarm service.
29 + */
30 +public final class AlarmServiceUtil {
31 +
32 + static Alarm lookupAlarm(AlarmId alarmId) {
33 + return alarmService().getAlarm(alarmId);
34 + }
35 +
36 + static Set<Alarm> lookUpAlarms() {
37 + return alarmService().getAlarms();
38 + }
39 +
40 + static Set<Alarm> lookUpAlarms(DeviceId deviceId) {
41 + return alarmService().getAlarms(deviceId);
42 + }
43 +
44 + static Map<Alarm.SeverityLevel, Long> lookUpAlarmCounts(DeviceId deviceId) {
45 + return alarmService().getAlarmCounts(deviceId);
46 + }
47 +
48 + static Map<Alarm.SeverityLevel, Long> lookUpAlarmCounts() {
49 + return alarmService().getAlarmCounts();
50 + }
51 +
52 + private static AlarmService alarmService() {
53 + return AbstractShellCommand.get(AlarmService.class);
54 + }
55 +
56 + private AlarmServiceUtil() {
57 + }
58 +}
1 +/*
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 +package org.onosproject.faultmanagement.alarms.gui;
17 +
18 +import com.google.common.collect.ImmutableList;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.onosproject.ui.UiExtension;
25 +import org.onosproject.ui.UiExtensionService;
26 +import org.onosproject.ui.UiMessageHandlerFactory;
27 +import org.onosproject.ui.UiView;
28 +import org.slf4j.Logger;
29 +import org.slf4j.LoggerFactory;
30 +
31 +import java.util.List;
32 +
33 +/**
34 + * Skeletal ONOS UI Table-View application component.
35 + */
36 +@Component(immediate = true)
37 +public class AlarmTableComponent {
38 +
39 + private static final String VIEW_ID = "alarmTable";
40 + private static final String VIEW_TEXT = "Alarms";
41 +
42 + private final Logger log = LoggerFactory.getLogger(getClass());
43 +
44 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
45 + protected UiExtensionService uiExtensionService;
46 +
47 + // List of application views
48 + private final List<UiView> uiViews = ImmutableList.of(
49 + new UiView(UiView.Category.OTHER, VIEW_ID, VIEW_TEXT)
50 + );
51 +
52 + // Factory for UI message handlers
53 + private final UiMessageHandlerFactory messageHandlerFactory =
54 + () -> ImmutableList.of(
55 + new AlarmTableMessageHandler()
56 + );
57 +
58 + // Application UI extension
59 + protected UiExtension extension =
60 + new UiExtension.Builder(getClass().getClassLoader(), uiViews)
61 + .resourcePath(VIEW_ID)
62 + .messageHandlerFactory(messageHandlerFactory)
63 + .build();
64 +
65 + @Activate
66 + protected void activate() {
67 + uiExtensionService.register(extension);
68 + log.info("Started");
69 + }
70 +
71 + @Deactivate
72 + protected void deactivate() {
73 + uiExtensionService.unregister(extension);
74 + log.info("Stopped");
75 + }
76 +
77 +}
1 +/*
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 +package org.onosproject.faultmanagement.alarms.gui;
17 +
18 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 +import com.google.common.base.Strings;
20 +import com.google.common.collect.ImmutableSet;
21 +import org.onosproject.ui.RequestHandler;
22 +import org.onosproject.ui.UiMessageHandler;
23 +import org.onosproject.ui.table.TableModel;
24 +import org.onosproject.ui.table.TableRequestHandler;
25 +import org.slf4j.Logger;
26 +import org.slf4j.LoggerFactory;
27 +
28 +import java.util.Collection;
29 +import java.util.Set;
30 +import org.joda.time.DateTime;
31 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
32 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
33 +import org.onosproject.net.DeviceId;
34 +import org.onosproject.ui.table.cell.TimeFormatter;
35 +
36 +/**
37 + * Skeletal ONOS UI Table-View message handler.
38 + */
39 +public class AlarmTableMessageHandler extends UiMessageHandler {
40 +
41 + private static final String ALARM_TABLE_DATA_REQ = "alarmTableDataRequest";
42 + private static final String ALARM_TABLE_DATA_RESP = "alarmTableDataResponse";
43 + private static final String ALARM_TABLES = "alarmTables";
44 +
45 + private static final String ALARM_TABLE_DETAIL_REQ = "alarmTableDetailsRequest";
46 + private static final String ALARM_TABLE_DETAIL_RESP = "alarmTableDetailsResponse";
47 + private static final String DETAILS = "details";
48 +
49 + private static final String ID = "id";
50 + private static final String DEVICE_ID_STR = "alarmDeviceId";
51 + private static final String DESCRIPTION = "alarmDesc";
52 + private static final String SOURCE = "alarmSource";
53 + private static final String TIME_RAISED = "alarmTimeRaised";
54 + private static final String TIME_UPDATED = "alarmTimeUpdated";
55 + private static final String TIME_CLEARED = "alarmTimeCleared";
56 + private static final String SEVERITY = "alarmSeverity";
57 + private static final String RESULT = "result";
58 +
59 + // TODO No need to show id column in ONOS-GUI
60 +
61 + // TODO Replace SEVERITY column by color-coding of row depending on severity ie. red=critical, green=cleared etc
62 + private static final String[] COLUMN_IDS = {ID, DEVICE_ID_STR, DESCRIPTION, SOURCE, TIME_RAISED, SEVERITY};
63 +
64 + private final Logger log = LoggerFactory.getLogger(getClass());
65 +
66 + @Override
67 + protected Collection<RequestHandler> createRequestHandlers() {
68 + return ImmutableSet.of(
69 + new AlarmTableDataRequestHandler(),
70 + new AlarmTableDetailRequestHandler()
71 + );
72 + }
73 +
74 + // handler for alarm table requests
75 + private final class AlarmTableDataRequestHandler extends TableRequestHandler {
76 +
77 + private AlarmTableDataRequestHandler() {
78 + super(ALARM_TABLE_DATA_REQ, ALARM_TABLE_DATA_RESP, ALARM_TABLES);
79 + }
80 +
81 + @Override
82 + protected String defaultColumnId() {
83 + // if necessary, override defaultColumnId() -- if it isn't "id"
84 + return ID;
85 + }
86 +
87 + @Override
88 + protected String[] getColumnIds() {
89 + return COLUMN_IDS;
90 + }
91 +
92 + @Override
93 + protected TableModel createTableModel() {
94 + // if required, override createTableModel() to set column formatters / comparators
95 + TableModel tm = super.createTableModel();
96 + tm.setFormatter(TIME_RAISED, new TimeFormatter());
97 + return tm;
98 + }
99 +
100 + @Override
101 + protected void populateTable(TableModel tm, ObjectNode payload) {
102 + log.debug(" populateTable tm={} payload ={}", tm, payload);
103 + String devId = string(payload, "devId");
104 +
105 + Set<Alarm> alarms = Strings.isNullOrEmpty(devId) ?
106 + AlarmServiceUtil.lookUpAlarms() :
107 + AlarmServiceUtil.lookUpAlarms(DeviceId.deviceId(devId));
108 +
109 + alarms.stream().forEach((alarm) -> {
110 + populateRow(tm.addRow(), alarm);
111 + });
112 +
113 + }
114 +
115 + private void populateRow(TableModel.Row row, Alarm alarm) {
116 + log.debug("populate table Row row={} item ={}", row, alarm);
117 +
118 + row.cell(ID, alarm.id().fingerprint())
119 + .cell(DEVICE_ID_STR, alarm.deviceId())
120 + .cell(DESCRIPTION, alarm.description())
121 + .cell(SOURCE, alarm.source())
122 + .cell(TIME_RAISED, new DateTime(alarm.timeRaised()))
123 + .cell(SEVERITY, alarm.severity());
124 + }
125 + }
126 +
127 + // handler for alarm details requests
128 + private final class AlarmTableDetailRequestHandler extends RequestHandler {
129 +
130 + private AlarmTableDetailRequestHandler() {
131 + super(ALARM_TABLE_DETAIL_REQ);
132 + }
133 +
134 + @Override
135 + public void process(long sid, ObjectNode payload) {
136 + log.debug("sid={}, payload ={}", sid, payload);
137 +
138 + String id = string(payload, ID, "(none)");
139 + Alarm alarm = AlarmServiceUtil.lookupAlarm(AlarmId.alarmId(Long.parseLong(id)));
140 + ObjectNode rootNode = objectNode();
141 + ObjectNode data = objectNode();
142 + rootNode.set(DETAILS, data);
143 +
144 + if (alarm == null) {
145 + rootNode.put(RESULT, "Item with id '" + id + "' not found");
146 + log.warn("attempted to get item detail for id '{}'", id);
147 +
148 + } else {
149 + rootNode.put(RESULT, "Found item with id '" + id + "'");
150 +
151 + data.put(ID, alarm.id().fingerprint());
152 + data.put(DESCRIPTION, alarm.description());
153 + data.put(DEVICE_ID_STR, alarm.deviceId().toString());
154 + data.put(SOURCE, alarm.source().toString());
155 + long timeRaised = alarm.timeRaised();
156 + data.put(TIME_RAISED,
157 + formatTime(timeRaised)
158 + );
159 + data.put(TIME_UPDATED, formatTime(alarm.timeUpdated()));
160 + data.put(TIME_CLEARED, formatTime(alarm.timeCleared()));
161 + data.put(SEVERITY, alarm.severity().toString());
162 + }
163 + log.debug("send ={}", rootNode);
164 +
165 + sendMessage(ALARM_TABLE_DETAIL_RESP, 0, rootNode);
166 + }
167 + }
168 +
169 + private static String formatTime(Long msSinceStartOfEpoch) {
170 + if (msSinceStartOfEpoch == null) {
171 + return "-";
172 + }
173 + return new TimeFormatter().format(new DateTime(msSinceStartOfEpoch));
174 + }
175 +
176 +
177 +}
1 +/*
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 +package org.onosproject.faultmanagement.alarms.gui;
17 +
18 +import com.google.common.collect.ImmutableList;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.onosproject.ui.UiExtension;
25 +import org.onosproject.ui.UiExtensionService;
26 +import org.onosproject.ui.UiMessageHandlerFactory;
27 +import org.onosproject.ui.UiTopoOverlayFactory;
28 +import org.onosproject.ui.UiView;
29 +import org.onosproject.ui.UiViewHidden;
30 +import org.slf4j.Logger;
31 +import org.slf4j.LoggerFactory;
32 +
33 +import java.util.List;
34 +
35 +/**
36 + * Skeletal ONOS UI Topology-Overlay application component.
37 + */
38 +@Component(immediate = true)
39 +public class AlarmTopovComponent {
40 +
41 + private static final ClassLoader CL = AlarmTopovComponent.class.getClassLoader();
42 + private static final String VIEW_ID = "alarmTopov";
43 +
44 + private final Logger log = LoggerFactory.getLogger(getClass());
45 +
46 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
47 + protected UiExtensionService uiExtensionService;
48 +
49 + // List of application views
50 + private final List<UiView> uiViews = ImmutableList.of(
51 + new UiViewHidden(VIEW_ID)
52 + );
53 +
54 + // Factory for UI message handlers
55 + private final UiMessageHandlerFactory messageHandlerFactory =
56 + () -> ImmutableList.of(
57 + new AlarmTopovMessageHandler()
58 + );
59 +
60 + // Factory for UI topology overlays
61 + private final UiTopoOverlayFactory topoOverlayFactory =
62 + () -> ImmutableList.of(
63 + new AlarmTopovOverlay()
64 + );
65 +
66 + // Application UI extension
67 + protected UiExtension extension =
68 + new UiExtension.Builder(CL, uiViews)
69 + .resourcePath(VIEW_ID)
70 + .messageHandlerFactory(messageHandlerFactory)
71 + .topoOverlayFactory(topoOverlayFactory)
72 + .build();
73 +
74 + @Activate
75 + protected void activate() {
76 + uiExtensionService.register(extension);
77 + log.info("Started");
78 + }
79 +
80 + @Deactivate
81 + protected void deactivate() {
82 + uiExtensionService.unregister(extension);
83 + log.info("Stopped");
84 + }
85 +
86 +}
1 +/*
2 + * Copyright 2014,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 +package org.onosproject.faultmanagement.alarms.gui;
17 +
18 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 +import com.google.common.base.Strings;
20 +import com.google.common.collect.ImmutableSet;
21 +import org.onlab.osgi.ServiceDirectory;
22 +import org.onosproject.net.Device;
23 +import org.onosproject.net.DeviceId;
24 +import org.onosproject.net.Element;
25 +import org.onosproject.net.HostId;
26 +import org.onosproject.net.device.DeviceService;
27 +import org.onosproject.net.host.HostService;
28 +import org.onosproject.ui.RequestHandler;
29 +import org.onosproject.ui.UiConnection;
30 +import org.onosproject.ui.UiMessageHandler;
31 +import org.onosproject.ui.topo.DeviceHighlight;
32 +import org.onosproject.ui.topo.Highlights;
33 +import org.onosproject.ui.topo.NodeBadge;
34 +import org.onosproject.ui.topo.NodeBadge.Status;
35 +import org.onosproject.ui.topo.TopoJson;
36 +import org.slf4j.Logger;
37 +import org.slf4j.LoggerFactory;
38 +
39 +import java.util.Collection;
40 +import java.util.Set;
41 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
42 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
43 +
44 +/**
45 + * Skeletal ONOS UI Topology-Overlay message handler.
46 + */
47 +public class AlarmTopovMessageHandler extends UiMessageHandler {
48 +
49 + private static final String ALARM_TOPOV_DISPLAY_START = "alarmTopovDisplayStart";
50 + private static final String ALARM_TOPOV_DISPLAY_UPDATE = "alarmTopovDisplayUpdate";
51 + private static final String ALARM_TOPOV_DISPLAY_STOP = "alarmTopovDisplayStop";
52 +
53 + private static final String ID = "id";
54 + private static final String MODE = "mode";
55 +
56 + private enum Mode {
57 +
58 + IDLE, MOUSE
59 + }
60 +
61 + private final Logger log = LoggerFactory.getLogger(getClass());
62 +
63 + private DeviceService deviceService;
64 + private HostService hostService;
65 + private AlarmService alarmService;
66 +
67 + private Mode currentMode = Mode.IDLE;
68 + private Element elementOfNote;
69 +
70 + // ===============-=-=-=-=-=-======================-=-=-=-=-=-=-================================
71 + @Override
72 + public void init(UiConnection connection, ServiceDirectory directory) {
73 + super.init(connection, directory);
74 + deviceService = directory.get(DeviceService.class);
75 + hostService = directory.get(HostService.class);
76 + alarmService = directory.get(AlarmService.class);
77 + }
78 +
79 + @Override
80 + protected Collection<RequestHandler> createRequestHandlers() {
81 + return ImmutableSet.of(
82 + new DisplayStartHandler(),
83 + new DisplayUpdateHandler(),
84 + new DisplayStopHandler()
85 + );
86 + }
87 +
88 + // === -------------------------
89 + // === Handler classes
90 + private final class DisplayStartHandler extends RequestHandler {
91 +
92 + public DisplayStartHandler() {
93 + super(ALARM_TOPOV_DISPLAY_START);
94 + }
95 +
96 + @Override
97 + public void process(long sid, ObjectNode payload) {
98 + String mode = string(payload, MODE);
99 +
100 + log.debug("Start Display: mode [{}]", mode);
101 + clearState();
102 + clearForMode();
103 +
104 + switch (mode) {
105 + case "mouse":
106 + currentMode = Mode.MOUSE;
107 +
108 + sendMouseData();
109 + break;
110 +
111 + default:
112 + currentMode = Mode.IDLE;
113 +
114 + break;
115 + }
116 + }
117 + }
118 +
119 + private final class DisplayUpdateHandler extends RequestHandler {
120 +
121 + public DisplayUpdateHandler() {
122 + super(ALARM_TOPOV_DISPLAY_UPDATE);
123 + }
124 +
125 + @Override
126 + public void process(long sid, ObjectNode payload) {
127 + String id = string(payload, ID);
128 + log.debug("Update Display: id [{}]", id);
129 + if (!Strings.isNullOrEmpty(id)) {
130 + updateForMode(id);
131 + } else {
132 + clearForMode();
133 + }
134 + }
135 + }
136 +
137 + private final class DisplayStopHandler extends RequestHandler {
138 +
139 + public DisplayStopHandler() {
140 + super(ALARM_TOPOV_DISPLAY_STOP);
141 + }
142 +
143 + @Override
144 + public void process(long sid, ObjectNode payload) {
145 + log.debug("Stop Display");
146 + clearState();
147 + clearForMode();
148 + }
149 + }
150 +
151 + // === ------------
152 + private void clearState() {
153 + currentMode = Mode.IDLE;
154 + elementOfNote = null;
155 + }
156 +
157 + private void updateForMode(String id) {
158 + log.debug("host service: {}", hostService);
159 + log.debug("device service: {}", deviceService);
160 +
161 + try {
162 + HostId hid = HostId.hostId(id);
163 + log.debug("host id {}", hid);
164 + elementOfNote = hostService.getHost(hid);
165 + log.debug("host element {}", elementOfNote);
166 +
167 + } catch (RuntimeException e) {
168 + try {
169 + DeviceId did = DeviceId.deviceId(id);
170 + log.debug("device id {}", did);
171 + elementOfNote = deviceService.getDevice(did);
172 + log.debug("device element {}", elementOfNote);
173 +
174 + } catch (RuntimeException e2) {
175 + log.debug("Unable to process ID [{}]", id);
176 + elementOfNote = null;
177 + }
178 + }
179 +
180 + switch (currentMode) {
181 + case MOUSE:
182 + sendMouseData();
183 + break;
184 +
185 + default:
186 + break;
187 + }
188 +
189 + }
190 +
191 + private void clearForMode() {
192 + sendHighlights(new Highlights());
193 + }
194 +
195 + private void sendHighlights(Highlights highlights) {
196 + sendMessage(TopoJson.highlightsMessage(highlights));
197 + }
198 +
199 + private void sendMouseData() {
200 + if (elementOfNote != null && elementOfNote instanceof Device) {
201 + DeviceId devId = (DeviceId) elementOfNote.id();
202 + Set<Alarm> alarmsOnDevice = alarmService.getAlarms(devId);
203 + Highlights highlights = new Highlights();
204 +
205 + addDeviceBadge(highlights, devId, alarmsOnDevice.size());
206 + sendHighlights(highlights);
207 + }
208 + // Note: could also process Host, if available
209 + }
210 +
211 + private void addDeviceBadge(Highlights h, DeviceId devId, int n) {
212 + DeviceHighlight dh = new DeviceHighlight(devId.toString());
213 + dh.setBadge(createBadge(n));
214 + h.add(dh);
215 + }
216 +
217 + private NodeBadge createBadge(int n) {
218 + Status status = n > 0 ? Status.ERROR : Status.INFO;
219 + String noun = n > 0 ? "(Alarmed)" : "(Normal)";
220 + String msg = "Alarms: " + n + " " + noun;
221 + return NodeBadge.number(status, n, msg);
222 + }
223 +
224 +}
1 +/*
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 +package org.onosproject.faultmanagement.alarms.gui;
17 +
18 +import java.util.Map;
19 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
20 +import org.onosproject.net.DeviceId;
21 +import org.onosproject.ui.UiTopoOverlay;
22 +import org.onosproject.ui.topo.ButtonId;
23 +import org.onosproject.ui.topo.PropertyPanel;
24 +import org.onosproject.ui.topo.TopoConstants.CoreButtons;
25 +import static org.onosproject.ui.topo.TopoConstants.Properties.*;
26 +
27 +/**
28 + * Our topology overlay.
29 + */
30 +public class AlarmTopovOverlay extends UiTopoOverlay {
31 +
32 + // NOTE: this must match the ID defined in alarmTopov.js
33 + private static final String OVERLAY_ID = "alarmsTopo-overlay";
34 +
35 + private static final ButtonId ALARM1_BUTTON = new ButtonId("alarm1button");
36 + private static final ButtonId ALARM2_BUTTON = new ButtonId("alarm2button");
37 +
38 + public AlarmTopovOverlay() {
39 + super(OVERLAY_ID);
40 + }
41 +
42 + @Override
43 + public void modifySummary(PropertyPanel pp) {
44 + pp.title("Alarms Overview");
45 + // We could just remove some properties here but lets keep it uncluttered, unless
46 + // there is feedback other properties are essential.
47 + pp.removeAllProps();
48 + Map<Alarm.SeverityLevel, Long> countsForAll = AlarmServiceUtil.lookUpAlarmCounts();
49 + addAlarmCountsProperties(pp, countsForAll);
50 +
51 + }
52 +
53 + @Override
54 + public void modifyDeviceDetails(PropertyPanel pp, DeviceId deviceId) {
55 + pp.title("Alarm Details");
56 + pp.removeProps(LATITUDE, LONGITUDE, PORTS, FLOWS, TUNNELS, SERIAL_NUMBER, PROTOCOL);
57 +
58 + Map<Alarm.SeverityLevel, Long> countsForDevice = AlarmServiceUtil.lookUpAlarmCounts(deviceId);
59 + addAlarmCountsProperties(pp, countsForDevice);
60 +
61 + pp.addButton(ALARM1_BUTTON)
62 + .addButton(ALARM2_BUTTON);
63 +
64 + pp.removeButtons(CoreButtons.SHOW_PORT_VIEW)
65 + .removeButtons(CoreButtons.SHOW_GROUP_VIEW);
66 + }
67 +
68 + private void addAlarmCountsProperties(PropertyPanel pp, Map<Alarm.SeverityLevel, Long> countsForDevice) {
69 +
70 + // TODO we could show these as color-coded squares with a count inside, to save space on the screen.
71 +
72 + long cr = countsForDevice.getOrDefault(Alarm.SeverityLevel.CRITICAL, 0L);
73 + long ma = countsForDevice.getOrDefault(Alarm.SeverityLevel.MAJOR, 0L);
74 + long mi = countsForDevice.getOrDefault(Alarm.SeverityLevel.MINOR, 0L);
75 + long wa = countsForDevice.getOrDefault(Alarm.SeverityLevel.WARNING, 0L);
76 + long in = countsForDevice.getOrDefault(Alarm.SeverityLevel.INDETERMINATE, 0L);
77 + long cl = countsForDevice.getOrDefault(Alarm.SeverityLevel.CLEARED, 0L);
78 +
79 + // Unfortunately the PropertyPanel does not righ justify numbers even when using longs,
80 + // but that not in scope of fault management work
81 + pp.addProp("Critical", cr);
82 + pp.addProp("Major", ma);
83 + pp.addProp("Minor", mi);
84 + pp.addProp("Warning", wa);
85 + pp.addProp("Indeter.", in);
86 + pp.addProp("Cleared", cl);
87 + pp.addSeparator();
88 + pp.addProp("Total", cr + ma + mi + wa + in + cl);
89 +
90 + }
91 +
92 +}
1 +/*
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 +
17 +/**
18 + * Fault Management GUI implementation.
19 + */
20 +package org.onosproject.faultmanagement.alarms.gui;
1 +<link rel="stylesheet" href="app/view/alarmTable/alarmTable.css">
...\ No newline at end of file ...\ No newline at end of file
1 +<script src="app/view/alarmTable/alarmTable.js"></script>
...\ No newline at end of file ...\ No newline at end of file
1 +<link rel="stylesheet" href="app/view/alarmTopov/alarmTopov.css">
1 +<script src="app/view/alarmTopov/alarmTopovDemo.js"></script>
2 +<script src="app/view/alarmTopov/alarmTopovOverlay.js"></script>
1 +/* css for alarm table view */
2 +
3 +#ov-alarm-table h2 {
4 + display: inline-block;
5 +}
6 +
7 +/* Panel Styling */
8 +#ov-alarm-table-item-details-panel.floatpanel {
9 + position: absolute;
10 + top: 115px;
11 +}
12 +
13 +.light #ov-alarm-table-item-details-panel.floatpanel {
14 + background-color: rgb(229, 234, 237);
15 +}
16 +.dark #ov-alarm-table-item-details-panel.floatpanel {
17 + background-color: #3A4042;
18 +}
19 +
20 +#ov-alarm-table-item-details-panel h3 {
21 + margin: 0;
22 + font-size: large;
23 +}
24 +
25 +#ov-alarm-table-item-details-panel h4 {
26 + margin: 0;
27 +}
28 +
29 +#ov-alarm-table-item-details-panel td {
30 + padding: 5px;
31 +}
32 +#ov-alarm-table-item-details-panel td.label {
33 + font-style: italic;
34 + opacity: 0.8;
35 +}
1 +<!-- partial HTML -->
2 +<div id="ov-alarm-table">
3 + <div class="tabular-header">
4 + <h2>Alarms for {{devId || "all devices."}} ({{tableData.length}} total)</h2>
5 + <div class="ctrl-btns">
6 + <div class="refresh" ng-class="{active: autoRefresh}"
7 + icon icon-id="refresh" icon-size="36"
8 + tooltip tt-msg="autoRefreshTip"
9 + ng-click="toggleRefresh()"></div>
10 + </div>
11 + </div>
12 +
13 + <div class="summary-list" onos-table-resize>
14 +
15 + <div class="table-header" onos-sortable-header>
16 + <table>
17 + <tr>
18 +
19 + <td colId="id" sortable>Id </td>
20 + <td colId="alarmDeviceId" sortable>Device </td>
21 + <td colId="alarmDesc" sortable>Description </td>
22 + <td colId="alarmSource" sortable>Source </td>
23 + <td colId="alarmTimeRaised" sortable>Time Raised </td>
24 + <td colId="alarmSeverity" sortable>Severity </td>
25 +
26 + </tr>
27 + </table>
28 + </div>
29 +
30 + <div class="table-body">
31 + <table>
32 + <tr ng-if="!tableData.length" class="no-data">
33 + <td colspan="3">
34 + No Alarms found
35 + </td>
36 + </tr>
37 +
38 + <tr ng-repeat="item in tableData track by $index"
39 + ng-click="selectCallback($event, item)"
40 + ng-class="{selected: item.id === selId}">
41 + <td>{{item.id}}</td>
42 + <td>{{item.alarmDeviceId}}</td>
43 + <td>{{item.alarmDesc}}</td>
44 + <td>{{item.alarmSource}}</td>
45 + <td>{{item.alarmTimeRaised}}</td>
46 + <td>{{item.alarmSeverity}}</td>
47 + </tr>
48 + </table>
49 + </div>
50 +
51 + </div>
52 +
53 + <ov-alarm-table-item-details-panel></ov-alarm-table-item-details-panel>
54 +</div>
1 +// js for alarm app table view
2 +(function () {
3 + 'use strict';
4 +
5 + // injected refs
6 + var $log, $scope, $loc, devId, fs, wss;
7 +
8 + // constants
9 + var detailsReq = 'alarmTableDetailsRequest',
10 + detailsResp = 'alarmTableDetailsResponse',
11 + pName = 'ov-alarm-table-item-details-panel',
12 + propOrder = ['id', 'alarmDeviceId', 'alarmDesc', 'alarmSource', 'alarmTimeRaised', 'alarmTimeUpdated', 'alarmTimeCleared', 'alarmSeverity'],
13 + friendlyProps = ['Alarm Id', 'Device Id', 'Description', 'Source', 'Time Raised', 'Time Updated', 'Time Cleared', 'Severity'];
14 +
15 +
16 + function addProp(tbody, index, value) {
17 + var tr = tbody.append('tr');
18 +
19 + function addCell(cls, txt) {
20 + tr.append('td').attr('class', cls).html(txt);
21 + }
22 + addCell('label', friendlyProps[index] + ' :');
23 + addCell('value', value);
24 + }
25 +
26 + function populatePanel(panel) {
27 + var title = panel.append('h3'),
28 + tbody = panel.append('table').append('tbody');
29 +
30 + title.text('Alarm Details');
31 +
32 + propOrder.forEach(function (prop, i) {
33 + addProp(tbody, i, $scope.panelDetails[prop]);
34 + });
35 +
36 + panel.append('hr');
37 + panel.append('h4').text('Comments');
38 + panel.append('p').text($scope.panelDetails.comment);
39 + }
40 +
41 + function respDetailsCb(data) {
42 + $scope.panelDetails = data.details;
43 + $scope.$apply();
44 + }
45 +
46 + angular.module('ovAlarmTable', [])
47 + .controller('OvAlarmTableCtrl',
48 + ['$log', '$scope', '$location', 'TableBuilderService',
49 + 'FnService', 'WebSocketService',
50 + function (_$log_, _$scope_, _$location_, tbs, _fs_, _wss_) {
51 + var params;
52 +
53 + $log = _$log_;
54 + $scope = _$scope_;
55 + $loc = _$location_;
56 +
57 + fs = _fs_;
58 + wss = _wss_;
59 +
60 +
61 + params = $loc.search();
62 + if (params.hasOwnProperty('devId')) {
63 + $scope.devId = params['devId'];
64 + }
65 +
66 + var handlers = {};
67 + $scope.panelDetails = {};
68 +
69 + // details response handler
70 + handlers[detailsResp] = respDetailsCb;
71 + wss.bindHandlers(handlers);
72 +
73 + // custom selection callback
74 + function selCb($event, row) {
75 + $log.debug("selCb row=" + JSON.stringify(row, null, 4) +
76 + ", $event=" + JSON.stringify($event, null, 4));
77 + $log.debug('$scope.selId=', $scope.selId);
78 + if ($scope.selId) {
79 + $log.debug('send');
80 + wss.sendEvent(detailsReq, {id: row.id});
81 + } else {
82 + $log.debug('hidePanel');
83 + $scope.hidePanel();
84 + }
85 + $log.debug('Got a click on:', row);
86 + }
87 +
88 + // TableBuilderService creating a table for us
89 + tbs.buildTable({
90 + scope: $scope,
91 + tag: 'alarmTable',
92 + selCb: selCb,
93 + query: params
94 + });
95 +
96 + // cleanup
97 + $scope.$on('$destroy', function () {
98 + wss.unbindHandlers(handlers);
99 + $log.log('OvAlarmTableCtrl has been destroyed');
100 + });
101 +
102 + $log.log('OvAlarmTableCtrl has been created');
103 + }])
104 +
105 + .directive('ovAlarmTableItemDetailsPanel', ['PanelService', 'KeyService',
106 + function (ps, ks) {
107 + return {
108 + restrict: 'E',
109 + link: function (scope, element, attrs) {
110 + // insert details panel with PanelService
111 + // create the panel
112 + var panel = ps.createPanel(pName, {
113 + width: 400,
114 + margin: 20,
115 + hideMargin: 0
116 + });
117 + panel.hide();
118 + scope.hidePanel = function () {
119 + panel.hide();
120 + };
121 +
122 + function closePanel() {
123 + if (panel.isVisible()) {
124 + $scope.selId = null;
125 + panel.hide();
126 + return true;
127 + }
128 + return false;
129 + }
130 +
131 + // create key bindings to handle panel
132 + ks.keyBindings({
133 + esc: [closePanel, 'Close the details panel'],
134 + _helpFormat: ['esc']
135 + });
136 + ks.gestureNotes([
137 + ['click', 'Select a row to show item details']
138 + ]);
139 +
140 + // update the panel's contents when the data is changed
141 + scope.$watch('panelDetails', function () {
142 + if (!fs.isEmptyObject(scope.panelDetails)) {
143 + panel.empty();
144 + populatePanel(panel);
145 + panel.show();
146 + }
147 + });
148 +
149 + // cleanup on destroyed scope
150 + scope.$on('$destroy', function () {
151 + ks.unbindKeys();
152 + ps.destroyPanel(pName);
153 + });
154 + }
155 + };
156 + }]);
157 +}());
1 +/*
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 +
17 +/*
18 + Alarm Demo module. This contains the "business logic" for the topology
19 + overlay that we are implementing.
20 + */
21 +
22 +(function () {
23 + 'use strict';
24 +
25 + // injected refs
26 + var $log, fs, flash, wss;
27 +
28 + // constants
29 + var displayStart = 'alarmTopovDisplayStart',
30 + displayUpdate = 'alarmTopovDisplayUpdate',
31 + displayStop = 'alarmTopovDisplayStop';
32 +
33 + // internal state
34 + var currentMode = null;
35 +
36 +
37 + // === ---------------------------
38 + // === Helper functions
39 +
40 + function sendDisplayStart(mode) {
41 + wss.sendEvent(displayStart, {
42 + mode: mode
43 + });
44 + }
45 +
46 + function sendDisplayUpdate(what) {
47 + wss.sendEvent(displayUpdate, {
48 + id: what ? what.id : ''
49 + });
50 + }
51 +
52 + function sendDisplayStop() {
53 + wss.sendEvent(displayStop);
54 + }
55 +
56 + // === ---------------------------
57 + // === Main API functions
58 +
59 + function startDisplay(mode) {
60 + if (currentMode === mode) {
61 + $log.debug('(in mode', mode, 'already)');
62 + } else {
63 + currentMode = mode;
64 + sendDisplayStart(mode);
65 + flash.flash('Starting display mode: ' + mode);
66 + }
67 + }
68 +
69 + function updateDisplay(m) {
70 + if (currentMode) {
71 + sendDisplayUpdate(m);
72 + }
73 + }
74 +
75 + function stopDisplay() {
76 + if (currentMode) {
77 + currentMode = null;
78 + sendDisplayStop();
79 + flash.flash('Canceling display mode');
80 + return true;
81 + }
82 + return false;
83 + }
84 +
85 + // === ---------------------------
86 + // === Module Factory Definition
87 +
88 + angular.module('ovAlarmTopov', [])
89 + .factory('AlarmTopovDemoService',
90 + ['$log', 'FnService', 'FlashService', 'WebSocketService',
91 +
92 + function (_$log_, _fs_, _flash_, _wss_) {
93 + $log = _$log_;
94 + fs = _fs_;
95 + flash = _flash_;
96 + wss = _wss_;
97 +
98 + return {
99 + startDisplay: startDisplay,
100 + updateDisplay: updateDisplay,
101 + stopDisplay: stopDisplay
102 + };
103 + }]);
104 +}());
1 +// alarm topology overlay - client side
2 +//
3 +// This is the glue that binds our business logic (in alarmTopovDemo.js)
4 +// to the overlay framework.
5 +
6 +(function () {
7 + 'use strict';
8 +
9 + // injected refs
10 + var $log, tov, stds, ns;
11 +
12 + // internal state should be kept in the service module (not here)
13 +
14 + // our overlay definition
15 + var overlay = {
16 + // NOTE: this must match the ID defined in AppUiTopovOverlay
17 + overlayId: 'alarmsTopo-overlay',
18 + glyphId: '*star4',
19 + tooltip: 'Alarms Overlay',
20 + // These glyphs get installed using the overlayId as a prefix.
21 + // e.g. 'star4' is installed as 'alarmsTopo-overlay-star4'
22 + // They can be referenced (from this overlay) as '*star4'
23 + // That is, the '*' prefix stands in for 'alarmsTopo-overlay-'
24 + glyphs: {
25 + star4: {
26 + vb: '0 0 8 8',
27 + // TODO new icon needed
28 + d: 'M1,4l2,-1l1,-2l1,2l2,1l-2,1l-1,2l-1,-2z'
29 + },
30 + banner: {
31 + vb: '0 0 6 6',
32 + // TODO new icon needed
33 + d: 'M1,1v4l2,-2l2,2v-4z'
34 + }
35 + },
36 + activate: function () {
37 + $log.debug("Alarm topology overlay ACTIVATED");
38 + },
39 + deactivate: function () {
40 + stds.stopDisplay();
41 + $log.debug("Alarm topology overlay DEACTIVATED");
42 + },
43 + // detail panel button definitions
44 + buttons: {
45 + alarm1button: {
46 + gid: 'chain',
47 + tt: 'Show alarms for this device',
48 + cb: function (data) {
49 + $log.debug('Show alarms for selected device. data:', data);
50 + ns.navTo("alarmTable", {devId: data.id});
51 +
52 + }
53 + },
54 + alarm2button: {
55 + gid: '*banner',
56 + tt: 'Show alarms for all devices',
57 + cb: function (data) {
58 + $log.debug('Show alarms for all devices. data:', data);
59 + ns.navTo("alarmTable");
60 +
61 + }
62 + }
63 + },
64 + // Key bindings for traffic overlay buttons
65 + // NOTE: fully qual. button ID is derived from overlay-id and key-name
66 + keyBindings: {
67 + 0: {
68 + cb: function () {
69 + stds.stopDisplay();
70 + },
71 + tt: 'Cancel Alarm Count on Device',
72 + gid: 'xMark'
73 + },
74 + V: {
75 + cb: function () {
76 + stds.startDisplay('mouse');
77 + },
78 + tt: 'Start Alarm Count on Device',
79 + gid: '*banner'
80 + },
81 + _keyOrder: [
82 + '0', 'V'
83 + ]
84 + },
85 + hooks: {
86 + // hook for handling escape key
87 + // Must return true to consume ESC, false otherwise.
88 + escape: function () {
89 + // Must return true to consume ESC, false otherwise.
90 + return stds.stopDisplay();
91 + },
92 + // hooks for when the selection changes...
93 + empty: function () {
94 + selectionCallback('empty');
95 + },
96 + single: function (data) {
97 + selectionCallback('single', data);
98 + },
99 + multi: function (selectOrder) {
100 + selectionCallback('multi', selectOrder);
101 + tov.addDetailButton('alarm1button');
102 + tov.addDetailButton('alarm2button');
103 + },
104 + mouseover: function (m) {
105 + // m has id, class, and type properties
106 + $log.debug('mouseover:', m);
107 + stds.updateDisplay(m);
108 + },
109 + mouseout: function () {
110 + $log.debug('mouseout');
111 + stds.updateDisplay();
112 + }
113 + }
114 + };
115 +
116 +
117 + function buttonCallback(x) {
118 + $log.debug('Toolbar-button callback', x);
119 + }
120 +
121 + function selectionCallback(x, d) {
122 + $log.debug('Selection callback', x, d);
123 + }
124 +
125 + // invoke code to register with the overlay service
126 + angular.module('ovAlarmTopov')
127 + .run(['$log', 'TopoOverlayService', 'AlarmTopovDemoService', 'NavService',
128 + function (_$log_, _tov_, _stds_, _ns_) {
129 + $log = _$log_;
130 + tov = _tov_;
131 + stds = _stds_;
132 + ns = _ns_;
133 + tov.register(overlay);
134 + }]);
135 +
136 +}());
1 +<!-- partial HTML -->
2 +<div id="ov-alarm-topov">
3 + <p>This is a hidden view .. just a placeholder to house the javascript</p>
4 +</div>
1 +<link rel="stylesheet" href="app/view/alarmCustom/alarmCustom.css">
...\ No newline at end of file ...\ No newline at end of file
1 +<script src="app/view/alarmCustom/alarmCustom.js"></script>
...\ No newline at end of file ...\ No newline at end of file
1 +# Need to write unit tests for the GUI server-side code ; write them after there are examples at web/gui/src/test/java/org/onosproject/ui/impl
...\ No newline at end of file ...\ No newline at end of file
...@@ -45,6 +45,11 @@ ...@@ -45,6 +45,11 @@
45 <version>${project.version}</version> 45 <version>${project.version}</version>
46 </dependency> 46 </dependency>
47 <dependency> 47 <dependency>
48 + <groupId>org.onosproject</groupId>
49 + <artifactId>onos-snmp-provider-alarm</artifactId>
50 + <version>${project.version}</version>
51 + </dependency>
52 + <dependency>
48 <groupId>org.osgi</groupId> 53 <groupId>org.osgi</groupId>
49 <artifactId>org.osgi.compendium</artifactId> 54 <artifactId>org.osgi.compendium</artifactId>
50 <version>5.0.0</version> 55 <version>5.0.0</version>
......
...@@ -15,13 +15,16 @@ ...@@ -15,13 +15,16 @@
15 */ 15 */
16 package org.onosproject.faultmanagement.impl; 16 package org.onosproject.faultmanagement.impl;
17 17
18 -import static com.google.common.base.Strings.isNullOrEmpty; 18 +import static com.google.common.base.Preconditions.checkNotNull;
19 import java.util.Dictionary; 19 import java.util.Dictionary;
20 import java.util.HashSet; 20 import java.util.HashSet;
21 import java.util.Map; 21 import java.util.Map;
22 import java.util.Set; 22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap; 23 import java.util.concurrent.ConcurrentHashMap;
24 -import java.util.concurrent.atomic.AtomicLong; 24 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
25 +import java.util.concurrent.ScheduledExecutorService;
26 +import java.util.stream.Collectors;
27 +import org.apache.commons.collections.CollectionUtils;
25 import org.apache.felix.scr.annotations.Activate; 28 import org.apache.felix.scr.annotations.Activate;
26 import org.apache.felix.scr.annotations.Component; 29 import org.apache.felix.scr.annotations.Component;
27 import org.apache.felix.scr.annotations.Deactivate; 30 import org.apache.felix.scr.annotations.Deactivate;
...@@ -47,8 +50,15 @@ import org.onosproject.core.CoreService; ...@@ -47,8 +50,15 @@ import org.onosproject.core.CoreService;
47 import org.apache.felix.scr.annotations.Reference; 50 import org.apache.felix.scr.annotations.Reference;
48 import org.apache.felix.scr.annotations.ReferenceCardinality; 51 import org.apache.felix.scr.annotations.ReferenceCardinality;
49 import org.onlab.util.ItemNotFoundException; 52 import org.onlab.util.ItemNotFoundException;
53 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider;
50 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm; 54 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
55 +import org.onosproject.net.device.DeviceService;
51 import org.osgi.service.component.ComponentContext; 56 import org.osgi.service.component.ComponentContext;
57 +import static java.util.concurrent.TimeUnit.SECONDS;
58 +
59 +import java.util.concurrent.atomic.AtomicLong;
60 +import static org.onlab.util.Tools.groupedThreads;
61 +import org.onosproject.net.Device;
52 62
53 /** 63 /**
54 * Implementation of the Alarm service. 64 * Implementation of the Alarm service.
...@@ -57,89 +67,133 @@ import org.osgi.service.component.ComponentContext; ...@@ -57,89 +67,133 @@ import org.osgi.service.component.ComponentContext;
57 @Service 67 @Service
58 public class AlarmsManager implements AlarmService { 68 public class AlarmsManager implements AlarmService {
59 69
70 + // For subscribing to device-related events
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 protected CoreService coreService; 72 protected CoreService coreService;
73 +
74 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 + protected DeviceService deviceService;
76 +
77 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 + protected AlarmProvider alarmProvider;
79 +
62 private final Logger log = getLogger(getClass()); 80 private final Logger log = getLogger(getClass());
63 private ApplicationId appId; 81 private ApplicationId appId;
64 private IdGenerator idGenerator; 82 private IdGenerator idGenerator;
65 83
84 + private ScheduledExecutorService alarmPollExecutor;
85 +
86 + // dummy data
87 + private final AtomicLong alarmIdGenerator = new AtomicLong(0);
66 88
67 - @Property(name = "fmDevices", value = "127.0.0.1", label = "Instance-specific configurations") 89 + private AlarmId generateAlarmId() {
68 - private String devConfigs; 90 + return AlarmId.alarmId(alarmIdGenerator.incrementAndGet());
91 + }
69 92
70 - private final Map<AlarmId, Alarm> alarms = new ConcurrentHashMap<>(); 93 + private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 120;
94 + @Property(name = "alarmPollFrequencySeconds", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
95 + label = "Frequency (in seconds) for polling alarm from devices")
96 + private int alarmPollFrequencySeconds = DEFAULT_POLL_FREQUENCY_SECONDS;
71 97
98 + // TODO implement purging of old alarms.
99 + private static final int DEFAULT_CLEAR_FREQUENCY_SECONDS = 500;
100 + @Property(name = "clearedAlarmPurgeSeconds", intValue = DEFAULT_CLEAR_FREQUENCY_SECONDS,
101 + label = "Frequency (in seconds) for deleting cleared alarms")
102 + private int clearedAlarmPurgeFrequencySeconds = DEFAULT_CLEAR_FREQUENCY_SECONDS;
72 103
73 - private final AtomicLong alarmIdGenerator = new AtomicLong(0); 104 + // TODO Later should must be persisted to disk or database
105 + private final Map<AlarmId, Alarm> alarms = new ConcurrentHashMap<>();
74 106
75 @Override 107 @Override
76 - public Alarm update(Alarm replacement) { 108 + public Alarm updateBookkeepingFields(AlarmId id, boolean isAcknowledged, String assignedUser) {
109 +
110 + Alarm found = alarms.get(id);
111 + if (found == null) {
112 + throw new ItemNotFoundException("Alarm with id " + id + " found");
113 + }
114 +
115 + Alarm updated = new DefaultAlarm.Builder(found).
116 + withAcknowledged(isAcknowledged).
117 + withAssignedUser(assignedUser).build();
118 + alarms.put(id, updated);
119 + return updated;
120 + }
121 +
122 + public Alarm clear(AlarmId id) {
77 123
78 - final Alarm found = alarms.get(replacement.id()); 124 + Alarm found = alarms.get(id);
79 if (found == null) { 125 if (found == null) {
80 - throw new ItemNotFoundException("Alarm with id " + replacement.id() + " found"); 126 + log.warn("id {} cant be cleared as it is already gone.", id);
127 + return null;
81 } 128 }
82 - final Alarm updated = new DefaultAlarm.Builder(found). 129 + Alarm updated = new DefaultAlarm.Builder(found).clear().build();
83 - withAcknowledged(replacement.acknowledged()). 130 + alarms.put(id, updated);
84 - withAssignedUser(replacement.assignedUser()).build();
85 - alarms.put(replacement.id(), updated);
86 return updated; 131 return updated;
87 } 132 }
88 133
89 @Override 134 @Override
90 - public int getActiveAlarmCount(DeviceId deviceId) { 135 + public Map<Alarm.SeverityLevel, Long> getAlarmCounts(DeviceId deviceId) {
91 - //TODO 136 +
92 - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); 137 + return getAlarms(deviceId).stream().collect(
138 + Collectors.groupingBy(Alarm::severity, Collectors.counting()));
139 +
140 + }
141 +
142 + @Override
143 + public Map<Alarm.SeverityLevel, Long> getAlarmCounts() {
144 +
145 + return getAlarms().stream().collect(
146 + Collectors.groupingBy(Alarm::severity, Collectors.counting()));
93 } 147 }
148 +
149 +
94 private static final String NOT_SUPPORTED_YET = "Not supported yet."; 150 private static final String NOT_SUPPORTED_YET = "Not supported yet.";
95 151
96 @Override 152 @Override
97 public Alarm getAlarm(AlarmId alarmId) { 153 public Alarm getAlarm(AlarmId alarmId) {
98 return nullIsNotFound( 154 return nullIsNotFound(
99 - alarms.get(alarmId), 155 + alarms.get(
156 + checkNotNull(alarmId, "Alarm Id cannot be null")),
100 "Alarm is not found"); 157 "Alarm is not found");
101 } 158 }
102 159
103 @Override 160 @Override
104 public Set<Alarm> getAlarms() { 161 public Set<Alarm> getAlarms() {
105 - //TODO 162 + return new HashSet<>(alarms.values());
106 - throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
107 } 163 }
108 164
109 @Override 165 @Override
110 public Set<Alarm> getActiveAlarms() { 166 public Set<Alarm> getActiveAlarms() {
111 - // Enpty set if no values 167 + return alarms.values().stream().filter(
112 - return alarms.isEmpty() ? new HashSet<>() : new HashSet<>(alarms.values()); 168 + a -> !a.severity().equals(Alarm.SeverityLevel.CLEARED)).
113 - 169 + collect(Collectors.toSet());
114 - }
115 -
116 - private static DefaultAlarm generateFake(DeviceId deviceId, AlarmId alarmId) {
117 -
118 - return new DefaultAlarm.Builder(
119 - alarmId, deviceId, "NE is not reachable", Alarm.SeverityLevel.MAJOR, System.currentTimeMillis()).
120 - withTimeUpdated(System.currentTimeMillis()).
121 - withServiceAffecting(true)
122 - .withAcknowledged(true).
123 - withManuallyClearable(true)
124 - .withAssignedUser("user1").build();
125 } 170 }
126 171
127 @Override 172 @Override
128 public Set<Alarm> getAlarms(Alarm.SeverityLevel severity) { 173 public Set<Alarm> getAlarms(Alarm.SeverityLevel severity) {
129 - //TODO 174 + return alarms.values().stream().filter(
130 - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); 175 + a -> a.severity().equals(severity)).
176 + collect(Collectors.toSet());
131 } 177 }
132 178
133 @Override 179 @Override
134 public Set<Alarm> getAlarms(DeviceId deviceId) { 180 public Set<Alarm> getAlarms(DeviceId deviceId) {
135 - //TODO 181 + return alarms.values().stream().filter(
136 - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); 182 + a -> deviceId.equals(a.deviceId())).
183 + collect(Collectors.toSet());
184 + }
185 +
186 + private Set<Alarm> getActiveAlarms(DeviceId deviceId) {
187 + return getActiveAlarms().stream().filter(
188 + a -> deviceId.equals(a.deviceId())).
189 + collect(Collectors.toSet());
137 } 190 }
138 191
139 @Override 192 @Override
140 public Set<Alarm> getAlarms(DeviceId deviceId, AlarmEntityId source) { 193 public Set<Alarm> getAlarms(DeviceId deviceId, AlarmEntityId source) {
141 - //TODO 194 + return getAlarms(deviceId).stream().filter(
142 - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); 195 + a -> source.equals(a.source())
196 + ).collect(Collectors.toSet());
143 } 197 }
144 198
145 @Override 199 @Override
...@@ -154,41 +208,92 @@ public class AlarmsManager implements AlarmService { ...@@ -154,41 +208,92 @@ public class AlarmsManager implements AlarmService {
154 throw new UnsupportedOperationException(NOT_SUPPORTED_YET); 208 throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
155 } 209 }
156 210
157 - private void discoverAlarmsForDevice(DeviceId deviceId) { 211 + private final AlarmListener alarmListener = new InternalAlarmListener();
158 - final AlarmId alarmId = new AlarmId(alarmIdGenerator.incrementAndGet());
159 -
160 - // TODO In a new thread invoke SNMP Provider with DeviceId and device type and when done update our of alarms
161 - //
162 - alarms.put(alarmId, generateFake(deviceId, alarmId));
163 -
164 - }
165 212
166 private class InternalAlarmListener implements AlarmListener { 213 private class InternalAlarmListener implements AlarmListener {
167 214
168 @Override 215 @Override
169 public void event(AlarmEvent event) { 216 public void event(AlarmEvent event) {
170 - // TODO 217 + log.debug("AlarmsManager. InternalAlarmListener received {}", event);
171 - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); 218 + try {
219 +
220 + switch (event.type()) {
221 + case DEVICE_DISCOVERY:
222 + DeviceId deviceId = checkNotNull(event.getDeviceRefreshed(), "Listener cannot be null");
223 + log.info("New alarm set for {} received!", deviceId);
224 + updateAlarms(event.subject(), deviceId);
225 + break;
226 +
227 + case NOTIFICATION:
228 + throw new IllegalArgumentException(
229 + "Alarm Notifications (Traps) not expected or implemented yet. Received =" + event);
230 + default:
231 + break;
232 + }
233 + } catch (Exception e) {
234 + log.warn("Failed to process {}", event, e);
235 + }
172 } 236 }
173 } 237 }
174 238
175 @Activate 239 @Activate
176 public void activate(ComponentContext context) { 240 public void activate(ComponentContext context) {
177 - log.info("Activate ..."); 241 + appId = coreService.registerApplication("org.onosproject.faultmanagement.alarms");
178 - appId = coreService.registerApplication("org.onos.faultmanagement.alarms");
179 idGenerator = coreService.getIdGenerator("alarm-ids"); 242 idGenerator = coreService.getIdGenerator("alarm-ids");
180 - log.info("Started with appId={} idGenerator={}", appId, idGenerator); 243 + log.info("Started with appId={}", appId);
244 +
245 + alarmProvider.addAlarmListener(alarmListener);
181 246
182 - final boolean result = modified(context); 247 + probeActiveDevices();
248 +
249 + boolean result = modified(context);
183 log.info("modified result = {}", result); 250 log.info("modified result = {}", result);
184 251
252 + alarmPollExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/fm", "alarms-poll-%d"));
253 + alarmPollExecutor.scheduleAtFixedRate(new PollAlarmsTask(),
254 + alarmPollFrequencySeconds, alarmPollFrequencySeconds, SECONDS);
255 +
256 + }
257 +
258 + /**
259 + * Auxiliary task to keep alarms up to date. IN future release alarm-notifications will be used as an optimization
260 + * so we dont have to wait until polling to detect changes. Furthermore with simple polling flapping alarms may be
261 + * missed.
262 + */
263 + private final class PollAlarmsTask implements Runnable {
264 +
265 + @Override
266 + public void run() {
267 + if (Thread.currentThread().isInterrupted()) {
268 + log.info("Interrupted, quitting");
269 + return;
270 + }
271 + try {
272 + probeActiveDevices();
273 + } catch (RuntimeException e) {
274 + log.error("Exception thrown during alarm synchronization process", e);
275 + }
276 + }
277 + }
278 +
279 + private void probeActiveDevices() {
280 + Iterable<Device> devices = deviceService.getAvailableDevices();
281 + log.info("Refresh alarms for all available devices={} ...", devices);
282 + for (Device d : devices) {
283 + log.info("Lets tell alarm provider to refresh alarms for {} ...", d.id());
284 + alarmProvider.triggerProbe(d.id());
285 + }
185 } 286 }
186 287
187 @Deactivate 288 @Deactivate
188 public void deactivate(ComponentContext context) { 289 public void deactivate(ComponentContext context) {
189 log.info("Deactivate ..."); 290 log.info("Deactivate ...");
190 - // cfgService.unregisterProperties(getClass(), false); 291 + alarmProvider.removeAlarmListener(alarmListener);
191 292
293 + if (alarmPollExecutor != null) {
294 + alarmPollExecutor.shutdownNow();
295 + }
296 + alarms.clear();
192 log.info("Stopped"); 297 log.info("Stopped");
193 } 298 }
194 299
...@@ -199,24 +304,36 @@ public class AlarmsManager implements AlarmService { ...@@ -199,24 +304,36 @@ public class AlarmsManager implements AlarmService {
199 log.info("No configuration file"); 304 log.info("No configuration file");
200 return false; 305 return false;
201 } 306 }
202 - final Dictionary<?, ?> properties = context.getProperties(); 307 + Dictionary<?, ?> properties = context.getProperties();
203 - final String ipaddresses = get(properties, "fmDevices"); 308 + String clearedAlarmPurgeSeconds = get(properties, "clearedAlarmPurgeSeconds");
204 - log.info("Settings: devConfigs={}", ipaddresses); 309 +
205 - if (!isNullOrEmpty(ipaddresses)) { 310 + log.info("Settings: clearedAlarmPurgeSeconds={}", clearedAlarmPurgeSeconds);
206 - discover(ipaddresses);
207 311
208 - }
209 return true; 312 return true;
210 } 313 }
211 314
212 - private void discover(String ipaddresses) { 315 + // Synchronised to prevent duplicate NE alarms being raised
213 - for (String deviceEntry : ipaddresses.split(",")) { 316 + synchronized void updateAlarms(Set<Alarm> discoveredSet, DeviceId deviceId) {
214 - final DeviceId deviceId = DeviceId.deviceId(deviceEntry); 317 + Set<Alarm> storedSet = getActiveAlarms(deviceId);
215 - if (deviceId != null) { 318 + log.trace("currentNeAlarms={}. discoveredAlarms={}", storedSet, discoveredSet);
216 - log.info("Device {} needs to have its alarms refreshed!", deviceId); 319 +
217 - discoverAlarmsForDevice(deviceId); 320 + if (CollectionUtils.isEqualCollection(storedSet, discoveredSet)) {
218 - } 321 + log.debug("Alarm lists are equivalent so no update for {}.", deviceId);
322 + return;
219 } 323 }
324 +
325 + storedSet.stream().filter(
326 + (stored) -> (!discoveredSet.contains(stored))).forEach((stored) -> {
327 + log.info("Alarm will be cleared as it is not on the element. Cleared alarm: {}.", stored);
328 + clear(stored.id());
329 + });
330 +
331 + discoveredSet.stream().filter(
332 + (discovered) -> (!storedSet.contains(discovered))).forEach((discovered) -> {
333 + log.info("Alarm will be raised as it is missing. New alarm: {}.", discovered);
334 + AlarmId id = generateAlarmId();
335 + alarms.put(id, new DefaultAlarm.Builder(discovered).withId(id).build());
336 + });
220 } 337 }
221 338
222 } 339 }
......
1 +/*
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 +package org.onosproject.faultmanagement.impl;
17 +
18 +import com.google.common.collect.Sets;
19 +import java.util.Collections;
20 +import java.util.HashMap;
21 +import java.util.HashSet;
22 +import java.util.Map;
23 +import org.junit.Test;
24 +import static org.junit.Assert.*;
25 +import org.onlab.util.ItemNotFoundException;
26 +import org.onosproject.net.DeviceId;
27 +import static org.hamcrest.Matchers.containsString;
28 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
29 +import static org.onosproject.incubator.net.faultmanagement.alarm.Alarm.SeverityLevel.*;
30 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
31 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
32 +import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
33 +
34 +public class AlarmsManagerTest {
35 +
36 + @Test
37 + public void testGettersWhenNoAlarms() {
38 + AlarmsManager am = new AlarmsManager();
39 + assertTrue("No alarms", am.getAlarms().isEmpty());
40 + assertTrue("No active alarms", am.getActiveAlarms().isEmpty());
41 + assertTrue("No alarms gives empty map per unknown device", am.getAlarmCounts(DeviceId.NONE).keySet().isEmpty());
42 + assertTrue("No alarms gives empty map", am.getAlarmCounts().keySet().isEmpty());
43 +
44 + assertEquals("Zero alarms for that device", 0, am.getAlarms(DeviceId.NONE).size());
45 + assertEquals("Zero major alarms", 0, am.getAlarms(Alarm.SeverityLevel.MAJOR).size());
46 +
47 + try {
48 + assertEquals("no alarms", 0, am.getAlarm(null));
49 + } catch (NullPointerException ex) {
50 + assertThat(ex.getMessage(),
51 + containsString("cannot be null"));
52 + }
53 +
54 + try {
55 + assertEquals("no alarms", 0, am.getAlarm(AlarmId.alarmId(1)));
56 + } catch (ItemNotFoundException ex) {
57 + assertThat(ex.getMessage(),
58 + containsString("not found"));
59 + }
60 + }
61 +
62 + @Test
63 + public void testAlarmUpdates() {
64 + AlarmsManager am = new AlarmsManager();
65 + assertTrue("no alarms", am.getAlarms().isEmpty());
66 +
67 + am.updateAlarms(new HashSet<>(), DEVICE_ID);
68 + assertTrue("still no alarms", am.getAlarms().isEmpty());
69 + Map<Alarm.SeverityLevel, Long> zeroAlarms = new CountsMapBuilder().create();
70 + assertEquals(zeroAlarms, am.getAlarmCounts());
71 + assertEquals(zeroAlarms, am.getAlarmCounts(DEVICE_ID));
72 +
73 + am.updateAlarms(Sets.newHashSet(ALARM_B, ALARM_A), DEVICE_ID);
74 + verifyGettingSetsOfAlarms(am, 2, 2);
75 + Map<Alarm.SeverityLevel, Long> critical2 = new CountsMapBuilder().with(CRITICAL, 2L).create();
76 + assertEquals(critical2, am.getAlarmCounts());
77 + assertEquals(critical2, am.getAlarmCounts(DEVICE_ID));
78 +
79 + am.updateAlarms(Sets.newHashSet(ALARM_A), DEVICE_ID);
80 + verifyGettingSetsOfAlarms(am, 2, 1);
81 + Map<Alarm.SeverityLevel, Long> critical1cleared1 =
82 + new CountsMapBuilder().with(CRITICAL, 1L).with(CLEARED, 1L).create();
83 + assertEquals(critical1cleared1, am.getAlarmCounts());
84 + assertEquals(critical1cleared1, am.getAlarmCounts(DEVICE_ID));
85 +
86 + // No change map when same alarms sent
87 + am.updateAlarms(Sets.newHashSet(ALARM_A), DEVICE_ID);
88 + verifyGettingSetsOfAlarms(am, 2, 1);
89 + assertEquals(critical1cleared1, am.getAlarmCounts());
90 + assertEquals(critical1cleared1, am.getAlarmCounts(DEVICE_ID));
91 +
92 + am.updateAlarms(Sets.newHashSet(ALARM_A, ALARM_A_WITHSRC), DEVICE_ID);
93 + verifyGettingSetsOfAlarms(am, 3, 2);
94 + Map<Alarm.SeverityLevel, Long> critical2cleared1 =
95 + new CountsMapBuilder().with(CRITICAL, 2L).with(CLEARED, 1L).create();
96 + assertEquals(critical2cleared1, am.getAlarmCounts());
97 + assertEquals(critical2cleared1, am.getAlarmCounts(DEVICE_ID));
98 +
99 + am.updateAlarms(Sets.newHashSet(), DEVICE_ID);
100 + verifyGettingSetsOfAlarms(am, 3, 0);
101 + assertEquals(new CountsMapBuilder().with(CLEARED, 3L).create(), am.getAlarmCounts(DEVICE_ID));
102 +
103 + assertEquals("No alarms for unknown devices", zeroAlarms, am.getAlarmCounts(DeviceId.NONE));
104 + assertEquals("No alarms for unknown devices", zeroAlarms, am.getAlarmCounts(DeviceId.deviceId("junk:junk")));
105 +
106 + }
107 +
108 + private void verifyGettingSetsOfAlarms(AlarmsManager am, int expectedTotal, int expectedActive) {
109 + assertEquals("Wrong total", expectedTotal, am.getAlarms().size());
110 + assertEquals("Wrong active count", expectedActive, am.getActiveAlarms().size());
111 + }
112 + private static final DeviceId DEVICE_ID = DeviceId.deviceId("foo:bar");
113 + private static final DefaultAlarm ALARM_A = new DefaultAlarm.Builder(
114 + DEVICE_ID, "aaa", Alarm.SeverityLevel.CRITICAL, 0).build();
115 +
116 + private static final DefaultAlarm ALARM_A_WITHSRC = new DefaultAlarm.Builder(
117 + ALARM_A).forSource(AlarmEntityId.alarmEntityId("port:foo")).build();
118 +
119 + private static final DefaultAlarm ALARM_B = new DefaultAlarm.Builder(
120 + DEVICE_ID, "bbb", Alarm.SeverityLevel.CRITICAL, 0).build();
121 +
122 + private static class CountsMapBuilder {
123 +
124 + private final Map<Alarm.SeverityLevel, Long> map = new HashMap<>();
125 +
126 + public CountsMapBuilder with(Alarm.SeverityLevel sev, Long count) {
127 + map.put(sev, count);
128 + return this;
129 + }
130 +
131 + public Map<Alarm.SeverityLevel, Long> create() {
132 + return Collections.unmodifiableMap(map);
133 + }
134 + }
135 +
136 +}
...@@ -124,6 +124,7 @@ ...@@ -124,6 +124,7 @@
124 com.fasterxml.jackson.core, 124 com.fasterxml.jackson.core,
125 org.apache.karaf.shell.commands, 125 org.apache.karaf.shell.commands,
126 org.apache.commons.lang.math.*, 126 org.apache.commons.lang.math.*,
127 + org.apache.commons.lang.*,
127 com.google.common.*, 128 com.google.common.*,
128 org.onlab.packet.*, 129 org.onlab.packet.*,
129 org.onlab.rest.*, 130 org.onlab.rest.*,
......
...@@ -66,28 +66,29 @@ public final class AlarmCodec extends JsonCodec<Alarm> { ...@@ -66,28 +66,29 @@ public final class AlarmCodec extends JsonCodec<Alarm> {
66 } 66 }
67 67
68 log.debug("id={}, full json={} ", json.get("id"), json); 68 log.debug("id={}, full json={} ", json.get("id"), json);
69 - final Long id = json.get("id").asLong(); 69 + Long id = json.get("id").asLong();
70 70
71 - final DeviceId deviceId = DeviceId.deviceId(json.get("deviceId").asText()); 71 + DeviceId deviceId = DeviceId.deviceId(json.get("deviceId").asText());
72 - final String description = json.get("description").asText(); 72 + String description = json.get("description").asText();
73 - final Long timeRaised = json.get("timeRaised").asLong(); 73 + Long timeRaised = json.get("timeRaised").asLong();
74 - final Long timeUpdated = json.get("timeUpdated").asLong(); 74 + Long timeUpdated = json.get("timeUpdated").asLong();
75 75
76 - final JsonNode jsonTimeCleared = json.get("timeCleared"); 76 + JsonNode jsonTimeCleared = json.get("timeCleared");
77 - final Long timeCleared = jsonTimeCleared == null || jsonTimeCleared.isNull() ? null : jsonTimeCleared.asLong(); 77 + Long timeCleared = jsonTimeCleared == null || jsonTimeCleared.isNull() ? null : jsonTimeCleared.asLong();
78 78
79 - final Alarm.SeverityLevel severity = Alarm.SeverityLevel.valueOf(json.get("severity").asText().toUpperCase()); 79 + Alarm.SeverityLevel severity = Alarm.SeverityLevel.valueOf(json.get("severity").asText().toUpperCase());
80 80
81 - final Boolean serviceAffecting = json.get("serviceAffecting").asBoolean(); 81 + Boolean serviceAffecting = json.get("serviceAffecting").asBoolean();
82 - final Boolean acknowledged = json.get("acknowledged").asBoolean(); 82 + Boolean acknowledged = json.get("acknowledged").asBoolean();
83 - final Boolean manuallyClearable = json.get("manuallyClearable").asBoolean(); 83 + Boolean manuallyClearable = json.get("manuallyClearable").asBoolean();
84 84
85 - final JsonNode jsonAssignedUser = json.get("assignedUser"); 85 + JsonNode jsonAssignedUser = json.get("assignedUser");
86 - final String assignedUser 86 + String assignedUser
87 = jsonAssignedUser == null || jsonAssignedUser.isNull() ? null : jsonAssignedUser.asText(); 87 = jsonAssignedUser == null || jsonAssignedUser.isNull() ? null : jsonAssignedUser.asText();
88 88
89 return new DefaultAlarm.Builder( 89 return new DefaultAlarm.Builder(
90 - AlarmId.valueOf(id), deviceId, description, severity, timeRaised).forSource(AlarmEntityId.NONE). 90 + deviceId, description, severity, timeRaised).forSource(AlarmEntityId.NONE).
91 + withId(AlarmId.alarmId(id)).
91 withTimeUpdated(timeUpdated). 92 withTimeUpdated(timeUpdated).
92 withTimeCleared(timeCleared). 93 withTimeCleared(timeCleared).
93 withServiceAffecting(serviceAffecting). 94 withServiceAffecting(serviceAffecting).
......
1 /* 1 /*
2 - * Copyright 2014-2015 Open Networking Laboratory 2 + * Copyright 2015 Open Networking Laboratory
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
...@@ -34,7 +34,9 @@ import javax.ws.rs.PathParam; ...@@ -34,7 +34,9 @@ import javax.ws.rs.PathParam;
34 import javax.ws.rs.Produces; 34 import javax.ws.rs.Produces;
35 import javax.ws.rs.QueryParam; 35 import javax.ws.rs.QueryParam;
36 import javax.ws.rs.core.MediaType; 36 import javax.ws.rs.core.MediaType;
37 +import org.apache.commons.lang.StringUtils;
37 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService; 38 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
39 +import org.onosproject.net.DeviceId;
38 import org.slf4j.Logger; 40 import org.slf4j.Logger;
39 import static org.slf4j.LoggerFactory.getLogger; 41 import static org.slf4j.LoggerFactory.getLogger;
40 42
...@@ -48,31 +50,32 @@ public class AlarmsWebResource extends AbstractWebResource { ...@@ -48,31 +50,32 @@ public class AlarmsWebResource extends AbstractWebResource {
48 50
49 private final Logger log = getLogger(getClass()); 51 private final Logger log = getLogger(getClass());
50 52
51 - public AlarmsWebResource() {
52 - }
53 -
54 /** 53 /**
55 - * Get all alarms. Returns a list of all alarms across all devices. 54 + * Get alarms. Returns a list of alarms
56 * 55 *
57 - * @param includeCleared include recently cleared alarms in response 56 + * @param includeCleared (optional) include recently cleared alarms in response
57 + * @param devId (optional) include only for specified device
58 * @return JSON encoded set of alarms 58 * @return JSON encoded set of alarms
59 */ 59 */
60 @GET 60 @GET
61 @Produces(MediaType.APPLICATION_JSON) 61 @Produces(MediaType.APPLICATION_JSON)
62 - public Response getAlarms(@DefaultValue("false") @QueryParam("includeCleared") boolean includeCleared 62 + public Response getAlarms(@DefaultValue("false") @QueryParam("includeCleared") boolean includeCleared,
63 + @DefaultValue("") @QueryParam("devId") String devId
63 ) { 64 ) {
64 65
65 log.info("Requesting all alarms, includeCleared={}", includeCleared); 66 log.info("Requesting all alarms, includeCleared={}", includeCleared);
66 - final AlarmService service = get(AlarmService.class); 67 + AlarmService service = get(AlarmService.class);
67 68
68 - final Iterable<Alarm> alarms = includeCleared 69 + Iterable<Alarm> alarms;
70 + if (StringUtils.isBlank(devId)) {
71 + alarms = includeCleared
69 ? service.getAlarms() 72 ? service.getAlarms()
70 : service.getActiveAlarms(); 73 : service.getActiveAlarms();
71 - 74 + } else {
72 - final ObjectNode result = new ObjectMapper().createObjectNode(); 75 + alarms = service.getAlarms(DeviceId.deviceId(devId));
73 - result.set("alarms", 76 + }
74 - codec(Alarm.class). 77 + ObjectNode result = new ObjectMapper().createObjectNode();
75 - encode(alarms, this)); 78 + result.set("alarms", new AlarmCodec().encode(alarms, this));
76 return ok(result.toString()).build(); 79 return ok(result.toString()).build();
77 80
78 } 81 }
...@@ -89,11 +92,11 @@ public class AlarmsWebResource extends AbstractWebResource { ...@@ -89,11 +92,11 @@ public class AlarmsWebResource extends AbstractWebResource {
89 public Response getAlarm(@PathParam("id") String id) { 92 public Response getAlarm(@PathParam("id") String id) {
90 log.info("HTTP GET alarm for id={}", id); 93 log.info("HTTP GET alarm for id={}", id);
91 94
92 - final AlarmId alarmId = toAlarmId(id); 95 + AlarmId alarmId = toAlarmId(id);
93 - final Alarm alarm = get(AlarmService.class).getAlarm(alarmId); 96 + Alarm alarm = get(AlarmService.class).getAlarm(alarmId);
94 97
95 - final ObjectNode result = mapper().createObjectNode(); 98 + ObjectNode result = new ObjectMapper().createObjectNode();
96 - result.set("alarm", codec(Alarm.class).encode(alarm, this)); 99 + result.set("alarm", new AlarmCodec().encode(alarm, this));
97 return ok(result.toString()).build(); 100 return ok(result.toString()).build();
98 } 101 }
99 102
...@@ -113,20 +116,22 @@ public class AlarmsWebResource extends AbstractWebResource { ...@@ -113,20 +116,22 @@ public class AlarmsWebResource extends AbstractWebResource {
113 log.info("PUT NEW ALARM at /{}", alarmIdPath); 116 log.info("PUT NEW ALARM at /{}", alarmIdPath);
114 117
115 try { 118 try {
116 - final ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); 119 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
117 log.info("jsonTree={}", jsonTree); 120 log.info("jsonTree={}", jsonTree);
118 121
119 - final Alarm alarm = codec(Alarm.class).decode(jsonTree, this); 122 + Alarm alarm = new AlarmCodec().decode(jsonTree, this);
120 123
121 - final AlarmService service = get(AlarmService.class); 124 + AlarmService service = get(AlarmService.class);
122 125
123 if (Long.parseLong(alarmIdPath) != alarm.id().fingerprint()) { 126 if (Long.parseLong(alarmIdPath) != alarm.id().fingerprint()) {
124 throw new IllegalArgumentException("id in path is " + Long.parseLong(alarmIdPath) 127 throw new IllegalArgumentException("id in path is " + Long.parseLong(alarmIdPath)
125 + " but payload uses id=" + alarm.id().fingerprint()); 128 + " but payload uses id=" + alarm.id().fingerprint());
126 129
127 } 130 }
128 - final Alarm updated = service.update(alarm); 131 + Alarm updated = service.updateBookkeepingFields(
129 - final ObjectNode encoded = new AlarmCodec().encode(updated, this); 132 + alarm.id(), alarm.acknowledged(), alarm.assignedUser()
133 + );
134 + ObjectNode encoded = new AlarmCodec().encode(updated, this);
130 return ok(encoded.toString()).build(); 135 return ok(encoded.toString()).build();
131 136
132 } catch (IOException ioe) { 137 } catch (IOException ioe) {
...@@ -136,7 +141,7 @@ public class AlarmsWebResource extends AbstractWebResource { ...@@ -136,7 +141,7 @@ public class AlarmsWebResource extends AbstractWebResource {
136 141
137 private static AlarmId toAlarmId(String id) { 142 private static AlarmId toAlarmId(String id) {
138 try { 143 try {
139 - return AlarmId.valueOf(Long.parseLong(id)); 144 + return AlarmId.alarmId(Long.parseLong(id));
140 } catch (NumberFormatException ex) { 145 } catch (NumberFormatException ex) {
141 throw new IllegalArgumentException("Alarm id should be numeric", ex); 146 throw new IllegalArgumentException("Alarm id should be numeric", ex);
142 } 147 }
......
...@@ -25,7 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; ...@@ -25,7 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
25 /** 25 /**
26 * Mock codec context for use in codec unit tests. 26 * Mock codec context for use in codec unit tests.
27 */ 27 */
28 -public class AlarmCodecContext implements CodecContext { 28 +public final class AlarmCodecContext implements CodecContext {
29 29
30 private final ObjectMapper mapper = new ObjectMapper(); 30 private final ObjectMapper mapper = new ObjectMapper();
31 private final CodecManager codecManager = new CodecManager(); 31 private final CodecManager codecManager = new CodecManager();
......
...@@ -36,37 +36,26 @@ import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm; ...@@ -36,37 +36,26 @@ import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
36 public class AlarmCodecTest { 36 public class AlarmCodecTest {
37 37
38 private final AlarmCodecContext context = new AlarmCodecContext(); 38 private final AlarmCodecContext context = new AlarmCodecContext();
39 + private static final AlarmId ALARM_ID = AlarmId.alarmId(44);
39 40
40 // Use this to check handling for miminal Alarm 41 // Use this to check handling for miminal Alarm
41 private final Alarm alarmMinimumFields = new DefaultAlarm.Builder( 42 private final Alarm alarmMinimumFields = new DefaultAlarm.Builder(
42 - new AlarmId(44), 43 + DeviceId.deviceId("of:2222000000000000"), "NE unreachable", Alarm.SeverityLevel.CLEARED, 1
43 - DeviceId.deviceId("of:2222000000000000"), 44 + ).withId(ALARM_ID).build();
44 - "NE unreachable",
45 - Alarm.SeverityLevel.CLEARED,
46 - 1).
47 - build();
48 45
49 // Use this to check handling for fully populated Alarm 46 // Use this to check handling for fully populated Alarm
50 private final Alarm alarmWithSource = new DefaultAlarm.Builder( 47 private final Alarm alarmWithSource = new DefaultAlarm.Builder(
51 - new AlarmId(44), 48 + DeviceId.deviceId("of:2222000000000000"), "NE unreachable", Alarm.SeverityLevel.CLEARED, 1
52 - DeviceId.deviceId("of:2222000000000000"), 49 + ).withId(ALARM_ID).forSource(AlarmEntityId.alarmEntityId("port:1/2/3/4")).withTimeUpdated(2).withTimeCleared(3L).
53 - "NE unreachable", 50 + withServiceAffecting(true).withAcknowledged(true).withManuallyClearable(true).
54 - Alarm.SeverityLevel.CLEARED, 1).
55 - forSource(AlarmEntityId.alarmEntityId("port:1/2/3/4")).
56 - withTimeUpdated(2).
57 - withTimeCleared(3L).
58 - withServiceAffecting(true).
59 - withAcknowledged(true).
60 - withManuallyClearable(true).
61 withAssignedUser("the assigned user").build(); 51 withAssignedUser("the assigned user").build();
62 52
63 @Test 53 @Test
64 public void alarmCodecTestWithOptionalFieldMissing() { 54 public void alarmCodecTestWithOptionalFieldMissing() {
65 - //context.registerService(AlarmService.class, new AlarmServiceAdapter()); 55 + JsonCodec<Alarm> codec = context.codec(Alarm.class);
66 - final JsonCodec<Alarm> codec = context.codec(Alarm.class);
67 assertThat(codec, is(notNullValue())); 56 assertThat(codec, is(notNullValue()));
68 57
69 - final ObjectNode alarmJson = codec.encode(alarmMinimumFields, context); 58 + ObjectNode alarmJson = codec.encode(alarmMinimumFields, context);
70 assertThat(alarmJson, notNullValue()); 59 assertThat(alarmJson, notNullValue());
71 assertThat(alarmJson, matchesAlarm(alarmMinimumFields)); 60 assertThat(alarmJson, matchesAlarm(alarmMinimumFields));
72 61
...@@ -74,10 +63,10 @@ public class AlarmCodecTest { ...@@ -74,10 +63,10 @@ public class AlarmCodecTest {
74 63
75 @Test 64 @Test
76 public void alarmCodecTestWithOptionalField() { 65 public void alarmCodecTestWithOptionalField() {
77 - final JsonCodec<Alarm> codec = context.codec(Alarm.class); 66 + JsonCodec<Alarm> codec = context.codec(Alarm.class);
78 assertThat(codec, is(notNullValue())); 67 assertThat(codec, is(notNullValue()));
79 68
80 - final ObjectNode alarmJson = codec.encode(alarmWithSource, context); 69 + ObjectNode alarmJson = codec.encode(alarmWithSource, context);
81 assertThat(alarmJson, notNullValue()); 70 assertThat(alarmJson, notNullValue());
82 assertThat(alarmJson, matchesAlarm(alarmWithSource)); 71 assertThat(alarmJson, matchesAlarm(alarmWithSource));
83 72
...@@ -85,9 +74,9 @@ public class AlarmCodecTest { ...@@ -85,9 +74,9 @@ public class AlarmCodecTest {
85 74
86 @Test 75 @Test
87 public void verifyMinimalAlarmIsEncoded() throws Exception { 76 public void verifyMinimalAlarmIsEncoded() throws Exception {
88 - final JsonCodec<Alarm> alarmCodec = context.codec(Alarm.class); 77 + JsonCodec<Alarm> alarmCodec = context.codec(Alarm.class);
89 78
90 - final Alarm alarm = getDecodedAlarm(alarmCodec, "alarm-minimal.json"); 79 + Alarm alarm = getDecodedAlarm(alarmCodec, "alarm-minimal.json");
91 assertCommon(alarm); 80 assertCommon(alarm);
92 81
93 assertThat(alarm.timeCleared(), nullValue()); 82 assertThat(alarm.timeCleared(), nullValue());
...@@ -97,9 +86,9 @@ public class AlarmCodecTest { ...@@ -97,9 +86,9 @@ public class AlarmCodecTest {
97 86
98 @Test 87 @Test
99 public void verifyFullyLoadedAlarmIsEncoded() throws Exception { 88 public void verifyFullyLoadedAlarmIsEncoded() throws Exception {
100 - final JsonCodec<Alarm> alarmCodec = context.codec(Alarm.class); 89 + JsonCodec<Alarm> alarmCodec = context.codec(Alarm.class);
101 90
102 - final Alarm alarm = getDecodedAlarm(alarmCodec, "alarm-full.json"); 91 + Alarm alarm = getDecodedAlarm(alarmCodec, "alarm-full.json");
103 assertCommon(alarm); 92 assertCommon(alarm);
104 93
105 assertThat(alarm.timeCleared(), is(2222L)); 94 assertThat(alarm.timeCleared(), is(2222L));
...@@ -108,7 +97,7 @@ public class AlarmCodecTest { ...@@ -108,7 +97,7 @@ public class AlarmCodecTest {
108 } 97 }
109 98
110 private void assertCommon(Alarm alarm) { 99 private void assertCommon(Alarm alarm) {
111 - assertThat(alarm.id(), is(new AlarmId(10L))); 100 + assertThat(alarm.id(), is(AlarmId.alarmId(10L)));
112 assertThat(alarm.description(), is("NE is not reachable")); 101 assertThat(alarm.description(), is("NE is not reachable"));
113 assertThat(alarm.source(), is(AlarmEntityId.NONE)); 102 assertThat(alarm.source(), is(AlarmEntityId.NONE));
114 assertThat(alarm.timeRaised(), is(999L)); 103 assertThat(alarm.timeRaised(), is(999L));
...@@ -127,14 +116,14 @@ public class AlarmCodecTest { ...@@ -127,14 +116,14 @@ public class AlarmCodecTest {
127 * @throws IOException if processing the resource fails to decode 116 * @throws IOException if processing the resource fails to decode
128 */ 117 */
129 private Alarm getDecodedAlarm(JsonCodec<Alarm> codec, String resourceName) throws IOException { 118 private Alarm getDecodedAlarm(JsonCodec<Alarm> codec, String resourceName) throws IOException {
130 - final InputStream jsonStream = AlarmCodecTest.class 119 + try (InputStream jsonStream = AlarmCodecTest.class
131 - .getResourceAsStream(resourceName); 120 + .getResourceAsStream(resourceName)) {
132 - final JsonNode json = context.mapper().readTree(jsonStream); 121 + JsonNode json = context.mapper().readTree(jsonStream);
133 assertThat(json, notNullValue()); 122 assertThat(json, notNullValue());
134 - final Alarm result = codec.decode((ObjectNode) json, context); 123 + Alarm result = codec.decode((ObjectNode) json, context);
135 assertThat(result, notNullValue()); 124 assertThat(result, notNullValue());
136 return result; 125 return result;
137 } 126 }
138 - 127 + }
139 128
140 } 129 }
......
...@@ -34,48 +34,48 @@ public final class AlarmJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> ...@@ -34,48 +34,48 @@ public final class AlarmJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode>
34 34
35 @Override 35 @Override
36 public boolean matchesSafely(JsonNode jsonAlarm, Description description) { 36 public boolean matchesSafely(JsonNode jsonAlarm, Description description) {
37 - final String jsonAlarmId = jsonAlarm.get("id").asText(); 37 + String jsonAlarmId = jsonAlarm.get("id").asText();
38 - final String alarmId = Long.toString(alarm.id().fingerprint()); 38 + String alarmId = Long.toString(alarm.id().fingerprint());
39 if (!jsonAlarmId.equals(alarmId)) { 39 if (!jsonAlarmId.equals(alarmId)) {
40 description.appendText("alarm id was " + jsonAlarmId); 40 description.appendText("alarm id was " + jsonAlarmId);
41 return false; 41 return false;
42 } 42 }
43 43
44 - final String jsonDeviceId = jsonAlarm.get("deviceId").asText(); 44 + String jsonDeviceId = jsonAlarm.get("deviceId").asText();
45 - final String alarmDeviceId = alarm.deviceId().toString(); 45 + String alarmDeviceId = alarm.deviceId().toString();
46 if (!jsonDeviceId.equals(alarmDeviceId)) { 46 if (!jsonDeviceId.equals(alarmDeviceId)) {
47 description.appendText("DeviceId was " + jsonDeviceId); 47 description.appendText("DeviceId was " + jsonDeviceId);
48 return false; 48 return false;
49 } 49 }
50 50
51 51
52 - final String jsonDescription = jsonAlarm.get("description").asText(); 52 + String jsonDescription = jsonAlarm.get("description").asText();
53 - final String alarmDesc = alarm.description(); 53 + String alarmDesc = alarm.description();
54 if (!jsonDescription.equals(alarmDesc)) { 54 if (!jsonDescription.equals(alarmDesc)) {
55 description.appendText("description was " + jsonDescription); 55 description.appendText("description was " + jsonDescription);
56 return false; 56 return false;
57 } 57 }
58 58
59 - final long jsonTimeRaised = jsonAlarm.get("timeRaised").asLong(); 59 + long jsonTimeRaised = jsonAlarm.get("timeRaised").asLong();
60 - final long timeRaised = alarm.timeRaised(); 60 + long timeRaised = alarm.timeRaised();
61 if (timeRaised != jsonTimeRaised) { 61 if (timeRaised != jsonTimeRaised) {
62 description.appendText("timeRaised was " + jsonTimeRaised); 62 description.appendText("timeRaised was " + jsonTimeRaised);
63 return false; 63 return false;
64 } 64 }
65 65
66 66
67 - final long jsonTimeUpdated = jsonAlarm.get("timeUpdated").asLong(); 67 + long jsonTimeUpdated = jsonAlarm.get("timeUpdated").asLong();
68 - final long timeUpdated = alarm.timeUpdated(); 68 + long timeUpdated = alarm.timeUpdated();
69 if (timeUpdated != jsonTimeUpdated) { 69 if (timeUpdated != jsonTimeUpdated) {
70 description.appendText("timeUpdated was " + jsonTimeUpdated); 70 description.appendText("timeUpdated was " + jsonTimeUpdated);
71 return false; 71 return false;
72 } 72 }
73 73
74 - final JsonNode jsonTimeClearedNode = jsonAlarm.get("timeCleared"); 74 + JsonNode jsonTimeClearedNode = jsonAlarm.get("timeCleared");
75 75
76 if (alarm.timeCleared() != null) { 76 if (alarm.timeCleared() != null) {
77 - final Long jsonTimeCleared = jsonTimeClearedNode.longValue(); 77 + Long jsonTimeCleared = jsonTimeClearedNode.longValue();
78 - final Long timeCleared = alarm.timeCleared(); 78 + Long timeCleared = alarm.timeCleared();
79 79
80 if (!timeCleared.equals(jsonTimeCleared)) { 80 if (!timeCleared.equals(jsonTimeCleared)) {
81 description.appendText("Time Cleared was " + jsonTimeCleared); 81 description.appendText("Time Cleared was " + jsonTimeCleared);
...@@ -89,18 +89,18 @@ public final class AlarmJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> ...@@ -89,18 +89,18 @@ public final class AlarmJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode>
89 } 89 }
90 } 90 }
91 91
92 - final String jsonSeverity = jsonAlarm.get("severity").asText(); 92 + String jsonSeverity = jsonAlarm.get("severity").asText();
93 - final String severity = alarm.severity().toString(); 93 + String severity = alarm.severity().toString();
94 if (!severity.equals(jsonSeverity)) { 94 if (!severity.equals(jsonSeverity)) {
95 description.appendText("severity was " + jsonSeverity); 95 description.appendText("severity was " + jsonSeverity);
96 return false; 96 return false;
97 } 97 }
98 98
99 - final JsonNode jsonAlarmNode = jsonAlarm.get("source"); 99 + JsonNode jsonAlarmNode = jsonAlarm.get("source");
100 100
101 if (alarm.source() != null) { 101 if (alarm.source() != null) {
102 - final String jsonSource = jsonAlarmNode.textValue(); 102 + String jsonSource = jsonAlarmNode.textValue();
103 - final String source = alarm.source().toString(); 103 + String source = alarm.source().toString();
104 104
105 if (!source.equals(jsonSource)) { 105 if (!source.equals(jsonSource)) {
106 description.appendText("source was " + jsonSource); 106 description.appendText("source was " + jsonSource);
......
...@@ -38,10 +38,10 @@ public class AlarmsWebResourceTest extends ResourceTest { ...@@ -38,10 +38,10 @@ public class AlarmsWebResourceTest extends ResourceTest {
38 @Before 38 @Before
39 public void setUp() { 39 public void setUp() {
40 40
41 - final CodecManager codecService = new CodecManager(); 41 + CodecManager codecService = new CodecManager();
42 codecService.activate(); 42 codecService.activate();
43 43
44 - final ServiceDirectory testDirectory = new TestServiceDirectory() 44 + ServiceDirectory testDirectory = new TestServiceDirectory()
45 // Currently no alarms-service implemented 45 // Currently no alarms-service implemented
46 // .add(AlarmsService.class, alarmsService) 46 // .add(AlarmsService.class, alarmsService)
47 .add(CodecService.class, codecService); 47 .add(CodecService.class, codecService);
...@@ -51,8 +51,8 @@ public class AlarmsWebResourceTest extends ResourceTest { ...@@ -51,8 +51,8 @@ public class AlarmsWebResourceTest extends ResourceTest {
51 @Test 51 @Test
52 @Ignore 52 @Ignore
53 public void getAllAlarms() { 53 public void getAllAlarms() {
54 - final WebResource rs = resource(); 54 + WebResource rs = resource();
55 - final String response = rs.path("/alarms").get(String.class); 55 + String response = rs.path("/alarms").get(String.class);
56 // Ensure hard-coded alarms returned okay 56 // Ensure hard-coded alarms returned okay
57 assertThat(response, containsString("\"NE is not reachable\",")); 57 assertThat(response, containsString("\"NE is not reachable\","));
58 assertThat(response, containsString("\"Equipment Missing\",")); 58 assertThat(response, containsString("\"Equipment Missing\","));
...@@ -61,8 +61,8 @@ public class AlarmsWebResourceTest extends ResourceTest { ...@@ -61,8 +61,8 @@ public class AlarmsWebResourceTest extends ResourceTest {
61 @Test 61 @Test
62 @Ignore 62 @Ignore
63 public void getAlarm() { 63 public void getAlarm() {
64 - final WebResource rs = resource(); 64 + WebResource rs = resource();
65 - final String response = rs.path("/alarms/1").get(String.class); 65 + String response = rs.path("/alarms/1").get(String.class);
66 // Ensure hard-coded alarms returned okay 66 // Ensure hard-coded alarms returned okay
67 assertThat(response, containsString("\"NE is not reachable\",")); 67 assertThat(response, containsString("\"NE is not reachable\","));
68 assertThat(response, not(containsString("\"Equipment Missing\","))); 68 assertThat(response, not(containsString("\"Equipment Missing\",")));
......
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- 2 <!--
3 - ~ Copyright 2014 Open Networking Laboratory 3 +~ Copyright 2015 Open Networking Laboratory
4 - ~ 4 +~
5 - ~ Licensed under the Apache License, Version 2.0 (the "License"); 5 +~ Licensed under the Apache License, Version 2.0 (the "License");
6 - ~ you may not use this file except in compliance with the License. 6 +~ you may not use this file except in compliance with the License.
7 - ~ You may obtain a copy of the License at 7 +~ You may obtain a copy of the License at
8 - ~ 8 +~
9 - ~ http://www.apache.org/licenses/LICENSE-2.0 9 +~ http://www.apache.org/licenses/LICENSE-2.0
10 - ~ 10 +~
11 - ~ Unless required by applicable law or agreed to in writing, software 11 +~ Unless required by applicable law or agreed to in writing, software
12 - ~ distributed under the License is distributed on an "AS IS" BASIS, 12 +~ distributed under the License is distributed on an "AS IS" BASIS,
13 - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 - ~ See the License for the specific language governing permissions and 14 +~ See the License for the specific language governing permissions and
15 - ~ limitations under the License. 15 +~ limitations under the License.
16 - --> 16 +-->
17 <project xmlns="http://maven.apache.org/POM/4.0.0" 17 <project xmlns="http://maven.apache.org/POM/4.0.0"
18 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 18 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 19 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
34 <modules> 34 <modules>
35 <module>fmmgr</module> 35 <module>fmmgr</module>
36 <module>fmweb</module> 36 <module>fmweb</module>
37 + <module>fmgui</module>
38 + <module>fmcli</module>
37 <module>app</module> 39 <module>app</module>
38 </modules> 40 </modules>
39 <dependencies> 41 <dependencies>
......
...@@ -15,51 +15,64 @@ ...@@ -15,51 +15,64 @@
15 */ 15 */
16 package org.onosproject.incubator.net.faultmanagement.alarm; 16 package org.onosproject.incubator.net.faultmanagement.alarm;
17 17
18 +import java.util.Set;
18 import org.onosproject.event.AbstractEvent; 19 import org.onosproject.event.AbstractEvent;
20 +import org.onosproject.net.DeviceId;
19 21
20 /** 22 /**
21 - * Entity that represents Alarm events. 23 + * Entity that represents Alarm events. Note: although the event will itself have a time, consumers may be more
24 + * interested in the times embedded in the alarms themselves.
25 + *
22 */ 26 */
23 -public class AlarmEvent extends AbstractEvent<AlarmEvent.Type, Alarm> { 27 +public class AlarmEvent extends AbstractEvent<AlarmEvent.Type, Set<Alarm>> {
24 28
29 + private final DeviceId deviceRefreshed;
25 30
26 /** 31 /**
27 - * Creates an event of a given type and for the specified alarm and the 32 + * Creates an event due to one or more notification.
28 - * current time.
29 * 33 *
30 - * @param type topology event type 34 + * @param alarms the set one or more of alarms.
31 - * @param alarm the alarm
32 */ 35 */
33 - public AlarmEvent(Type type, Alarm alarm) { 36 + public AlarmEvent(Set<Alarm> alarms) {
34 - super(type, alarm); 37 + super(Type.NOTIFICATION, alarms);
38 + deviceRefreshed = null;
35 } 39 }
36 40
37 /** 41 /**
38 - * Creates an event of a given type and for the specified alarm and time. 42 + * Creates an event due to alarm discovery for a device.
39 * 43 *
40 - * @param type link event type 44 + * @param alarms the set of alarms.
41 - * @param alarm the alarm 45 + * @param deviceRefreshed if of refreshed device, populated after a de-discovery
42 - * @param time occurrence time
43 */ 46 */
44 - public AlarmEvent(Type type, Alarm alarm, 47 + public AlarmEvent(Set<Alarm> alarms,
45 - long time) { 48 + DeviceId deviceRefreshed) {
46 - super(type, alarm, time); 49 + super(Type.DEVICE_DISCOVERY, alarms);
50 + this.deviceRefreshed = deviceRefreshed;
51 +
47 } 52 }
48 53
49 /** 54 /**
50 - * Type of alarm events. 55 + * Gets which device was refreshed.
56 + *
57 + * @return the refreshed device, or null if event related to a asynchronous notification(s)
51 */ 58 */
52 - public enum Type { 59 + public DeviceId getDeviceRefreshed() {
60 + return deviceRefreshed;
61 + }
62 +
53 /** 63 /**
54 - * A Raised Alarm. 64 + * Type of alarm event.
55 */ 65 */
56 - RAISE, 66 + public enum Type {
57 67
58 /** 68 /**
59 - * A Cleared Alarm. 69 + * Individual alarm(s) updated.
60 */ 70 */
61 - CLEAR 71 + NOTIFICATION,
72 + /**
73 + * Alarm set updated for a given device.
74 + */
75 + DEVICE_DISCOVERY,
62 } 76 }
63 77
64 -
65 } 78 }
......
...@@ -16,11 +16,9 @@ ...@@ -16,11 +16,9 @@
16 package org.onosproject.incubator.net.faultmanagement.alarm; 16 package org.onosproject.incubator.net.faultmanagement.alarm;
17 17
18 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.Beta;
19 -
20 import java.util.Objects; 19 import java.util.Objects;
21 -
22 import static com.google.common.base.MoreObjects.toStringHelper; 20 import static com.google.common.base.MoreObjects.toStringHelper;
23 - 21 +import static com.google.common.base.Preconditions.checkArgument;
24 /** 22 /**
25 * Alarm identifier suitable as an external key. 23 * Alarm identifier suitable as an external key.
26 * <p> 24 * <p>
...@@ -30,23 +28,29 @@ import static com.google.common.base.MoreObjects.toStringHelper; ...@@ -30,23 +28,29 @@ import static com.google.common.base.MoreObjects.toStringHelper;
30 public final class AlarmId { 28 public final class AlarmId {
31 29
32 private final long id; 30 private final long id;
31 + public static final AlarmId NONE = new AlarmId();
33 32
34 /** 33 /**
35 * Instantiates a new Alarm id. 34 * Instantiates a new Alarm id.
36 * 35 *
37 * @param id the id 36 * @param id the id
38 */ 37 */
39 - public AlarmId(final long id) { 38 + private AlarmId(long id) {
39 + checkArgument(id != 0L, "id must be non-zero");
40 this.id = id; 40 this.id = id;
41 } 41 }
42 42
43 + private AlarmId() {
44 + this.id = 0L;
45 + }
46 +
43 /** 47 /**
44 * Creates an alarm identifier from the specified long representation. 48 * Creates an alarm identifier from the specified long representation.
45 * 49 *
46 * @param value long value 50 * @param value long value
47 * @return intent identifier 51 * @return intent identifier
48 */ 52 */
49 - public static AlarmId valueOf(final long value) { 53 + public static AlarmId alarmId(long value) {
50 return new AlarmId(value); 54 return new AlarmId(value);
51 } 55 }
52 56
...@@ -65,12 +69,12 @@ public final class AlarmId { ...@@ -65,12 +69,12 @@ public final class AlarmId {
65 } 69 }
66 70
67 @Override 71 @Override
68 - public boolean equals(final Object obj) { 72 + public boolean equals(Object obj) {
69 if (this == obj) { 73 if (this == obj) {
70 return true; 74 return true;
71 } 75 }
72 if (obj instanceof AlarmId) { 76 if (obj instanceof AlarmId) {
73 - final AlarmId other = (AlarmId) obj; 77 + AlarmId other = (AlarmId) obj;
74 return Objects.equals(this.id, other.id); 78 return Objects.equals(this.id, other.id);
75 } 79 }
76 return false; 80 return false;
......
...@@ -24,14 +24,25 @@ import org.onosproject.net.provider.Provider; ...@@ -24,14 +24,25 @@ import org.onosproject.net.provider.Provider;
24 public interface AlarmProvider extends Provider { 24 public interface AlarmProvider extends Provider {
25 25
26 /** 26 /**
27 - * Triggers an asynchronous discovery of the alarms on the specified device, 27 + * Triggers an asynchronous discovery of the alarms on the specified device, intended to refresh internal alarm
28 - * intended to refresh internal alarm model for the device. An indirect 28 + * model for the device. An indirect result of this should be a event sent later with discovery result ie a set of
29 - * result of this should be invocation of 29 + * alarms.
30 - * {@link org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderService#updateAlarmList} )}
31 - * at some later point in time.
32 * 30 *
33 * @param deviceId ID of device to be probed 31 * @param deviceId ID of device to be probed
34 */ 32 */
35 void triggerProbe(DeviceId deviceId); 33 void triggerProbe(DeviceId deviceId);
36 34
35 + /**
36 + * Register a listener for alarms.
37 + *
38 + * @param listener the listener to notify
39 + */
40 + void addAlarmListener(AlarmListener listener);
41 +
42 + /**
43 + * Unregister a listener.
44 + *
45 + * @param listener the listener to unregister
46 + */
47 + void removeAlarmListener(AlarmListener listener);
37 } 48 }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.incubator.net.faultmanagement.alarm; 16 package org.onosproject.incubator.net.faultmanagement.alarm;
17 17
18 18
19 +import com.google.common.annotations.Beta;
19 import org.onosproject.net.DeviceId; 20 import org.onosproject.net.DeviceId;
20 import org.onosproject.net.provider.ProviderService; 21 import org.onosproject.net.provider.ProviderService;
21 22
...@@ -24,6 +25,7 @@ import java.util.Collection; ...@@ -24,6 +25,7 @@ import java.util.Collection;
24 /** 25 /**
25 * The interface Alarm provider service. 26 * The interface Alarm provider service.
26 */ 27 */
28 +@Beta
27 public interface AlarmProviderService extends ProviderService<AlarmProvider> { 29 public interface AlarmProviderService extends ProviderService<AlarmProvider> {
28 30
29 /** 31 /**
......
...@@ -16,60 +16,65 @@ ...@@ -16,60 +16,65 @@
16 package org.onosproject.incubator.net.faultmanagement.alarm; 16 package org.onosproject.incubator.net.faultmanagement.alarm;
17 17
18 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.Beta;
19 -//import org.onosproject.event.ListenerService; 19 +import java.util.Map;
20 20
21 import java.util.Set; 21 import java.util.Set;
22 import org.onosproject.net.ConnectPoint; 22 import org.onosproject.net.ConnectPoint;
23 import org.onosproject.net.DeviceId; 23 import org.onosproject.net.DeviceId;
24 24
25 /** 25 /**
26 - * Service for interacting with the alarm handling of devices. Unless stated 26 + * Service for interacting with the alarm handling of devices. Unless stated otherwise, getter methods
27 - * otherwise method return active AND recently-cleared alarms. 27 + * return active AND recently-cleared alarms.
28 */ 28 */
29 @Beta 29 @Beta
30 public interface AlarmService { 30 public interface AlarmService {
31 -// extends ListenerService<AlarmEvent, AlarmListener> {
32 31
33 /** 32 /**
34 - * Alarm should be updated in ONOS's internal representation; only 33 + * Update book-keeping (ie administrative) fields for the alarm matching the specified identifier.
35 - * administration/book-keeping fields may be updated. Attempting to update 34 + *
36 - * fields which are mapped directly from device is prohibited. 35 + * @param id alarm identifier
36 + * @param isAcknowledged new acknowledged state
37 + * @param assignedUser new assigned user, null clear
38 + * @return updated alarm (including any recent device-derived changes)
37 * 39 *
38 - * @param replacement alarm with updated book-keeping fields
39 - * @return updated alarm (including any recent device derived changes)
40 -
41 - * @throws java.lang.IllegalStateException if attempt to update not allowed
42 - * fields.
43 */ 40 */
44 - Alarm update(Alarm replacement); 41 + Alarm updateBookkeepingFields(AlarmId id, boolean isAcknowledged, String assignedUser);
45 42
46 /** 43 /**
47 - * Returns the number of ACTIVE alarms on a device. 44 + * Returns summary of alarms on a given device.
48 * 45 *
49 * @param deviceId the device 46 * @param deviceId the device
50 - * @return number of alarms 47 + * @return map of severity (if applicable) vs alarm counts; empty map if either the device has no alarms or
48 + * identified device is not managed.
51 */ 49 */
52 - int getActiveAlarmCount(DeviceId deviceId); 50 + Map<Alarm.SeverityLevel, Long> getAlarmCounts(DeviceId deviceId);
51 +
52 + /**
53 + * Returns summary of alarms on all devices.
54 + *
55 + * @return map of severity (if applicable) vs alarm counts; empty map if no alarms.
56 + */
57 + Map<Alarm.SeverityLevel, Long> getAlarmCounts();
53 58
54 /** 59 /**
55 * Returns the alarm with the specified identifier. 60 * Returns the alarm with the specified identifier.
56 * 61 *
57 * @param alarmId alarm identifier 62 * @param alarmId alarm identifier
58 - * @return alarm or null if one with the given identifier is not known 63 + * @return alarm matching id; null if no alarm matches the identifier.
59 */ 64 */
60 Alarm getAlarm(AlarmId alarmId); 65 Alarm getAlarm(AlarmId alarmId);
61 66
62 /** 67 /**
63 * Returns all of the alarms. 68 * Returns all of the alarms.
64 * 69 *
65 - * @return the alarms 70 + * @return set of alarms; empty set if no alarms
66 */ 71 */
67 Set<Alarm> getAlarms(); 72 Set<Alarm> getAlarms();
68 73
69 /** 74 /**
70 * Returns all of the ACTIVE alarms. Recently cleared alarms excluded. 75 * Returns all of the ACTIVE alarms. Recently cleared alarms excluded.
71 * 76 *
72 - * @return the alarms 77 + * @return set of alarms; empty set if no alarms
73 */ 78 */
74 Set<Alarm> getActiveAlarms(); 79 Set<Alarm> getActiveAlarms();
75 80
...@@ -77,16 +82,15 @@ public interface AlarmService { ...@@ -77,16 +82,15 @@ public interface AlarmService {
77 * Returns the alarms with the specified severity. 82 * Returns the alarms with the specified severity.
78 * 83 *
79 * @param severity the alarm severity 84 * @param severity the alarm severity
80 - * @return the active alarms with a particular severity 85 + * @return set of alarms with a particular severity; empty set if no alarms
81 */ 86 */
82 Set<Alarm> getAlarms(Alarm.SeverityLevel severity); 87 Set<Alarm> getAlarms(Alarm.SeverityLevel severity);
83 88
84 /** 89 /**
85 - * Returns the alarm for a given device, regardless of source within that 90 + * Returns the alarm matching a given device, regardless of source within that device.
86 - * device.
87 * 91 *
88 - * @param deviceId the device 92 + * @param deviceId the device to use when searching alarms.
89 - * @return the alarms 93 + * @return set of alarms; empty set if no alarms
90 */ 94 */
91 Set<Alarm> getAlarms(DeviceId deviceId); 95 Set<Alarm> getAlarms(DeviceId deviceId);
92 96
...@@ -95,7 +99,7 @@ public interface AlarmService { ...@@ -95,7 +99,7 @@ public interface AlarmService {
95 * 99 *
96 * @param deviceId the device 100 * @param deviceId the device
97 * @param source the source within the device 101 * @param source the source within the device
98 - * @return the alarms 102 + * @return set of alarms; empty set if no alarms
99 */ 103 */
100 Set<Alarm> getAlarms(DeviceId deviceId, AlarmEntityId source); 104 Set<Alarm> getAlarms(DeviceId deviceId, AlarmEntityId source);
101 105
...@@ -104,7 +108,7 @@ public interface AlarmService { ...@@ -104,7 +108,7 @@ public interface AlarmService {
104 * 108 *
105 * @param src one end of the link 109 * @param src one end of the link
106 * @param dst one end of the link 110 * @param dst one end of the link
107 - * @return the alarms 111 + * @return set of alarms; empty set if no alarms
108 */ 112 */
109 Set<Alarm> getAlarmsForLink(ConnectPoint src, ConnectPoint dst); 113 Set<Alarm> getAlarmsForLink(ConnectPoint src, ConnectPoint dst);
110 114
...@@ -113,9 +117,9 @@ public interface AlarmService { ...@@ -113,9 +117,9 @@ public interface AlarmService {
113 * 117 *
114 * @param deviceId the device 118 * @param deviceId the device
115 * @param flowId the flow 119 * @param flowId the flow
116 - * @return the alarms 120 + * @return set of alarms; empty set if no alarms
117 */ 121 */
118 Set<Alarm> getAlarmsForFlow(DeviceId deviceId, long flowId); 122 Set<Alarm> getAlarmsForFlow(DeviceId deviceId, long flowId);
119 123
120 -// Support retrieving alarms affecting other ONOS entity types may be added in future release 124 + // TODO Support retrieving alarms affecting other entity types may be added in future release
121 } 125 }
......
...@@ -145,14 +145,16 @@ public final class DefaultAlarm implements Alarm { ...@@ -145,14 +145,16 @@ public final class DefaultAlarm implements Alarm {
145 145
146 @Override 146 @Override
147 public int hashCode() { 147 public int hashCode() {
148 - return Objects.hash(id, deviceId, description, 148 + // id or timeRaised or timeUpdated may differ
149 - source, timeRaised, timeUpdated, timeCleared, severity, 149 + return Objects.hash(deviceId, description,
150 + source, timeCleared, severity,
150 isServiceAffecting, isAcknowledged, 151 isServiceAffecting, isAcknowledged,
151 isManuallyClearable, assignedUser); 152 isManuallyClearable, assignedUser);
152 } 153 }
153 154
154 @Override 155 @Override
155 public boolean equals(final Object obj) { 156 public boolean equals(final Object obj) {
157 + // Make sure equals() is tune with hashCode() so works ok in a hashSet !
156 if (obj == null) { 158 if (obj == null) {
157 return false; 159 return false;
158 } 160 }
...@@ -160,9 +162,8 @@ public final class DefaultAlarm implements Alarm { ...@@ -160,9 +162,8 @@ public final class DefaultAlarm implements Alarm {
160 return false; 162 return false;
161 } 163 }
162 final DefaultAlarm other = (DefaultAlarm) obj; 164 final DefaultAlarm other = (DefaultAlarm) obj;
163 - if (!Objects.equals(this.id, other.id)) { 165 +
164 - return false; 166 + // id or timeRaised or timeUpdated may differ
165 - }
166 if (!Objects.equals(this.deviceId, other.deviceId)) { 167 if (!Objects.equals(this.deviceId, other.deviceId)) {
167 return false; 168 return false;
168 } 169 }
...@@ -172,12 +173,7 @@ public final class DefaultAlarm implements Alarm { ...@@ -172,12 +173,7 @@ public final class DefaultAlarm implements Alarm {
172 if (!Objects.equals(this.source, other.source)) { 173 if (!Objects.equals(this.source, other.source)) {
173 return false; 174 return false;
174 } 175 }
175 - if (this.timeRaised != other.timeRaised) { 176 +
176 - return false;
177 - }
178 - if (this.timeUpdated != other.timeUpdated) {
179 - return false;
180 - }
181 if (!Objects.equals(this.timeCleared, other.timeCleared)) { 177 if (!Objects.equals(this.timeCleared, other.timeCleared)) {
182 return false; 178 return false;
183 } 179 }
...@@ -219,11 +215,11 @@ public final class DefaultAlarm implements Alarm { ...@@ -219,11 +215,11 @@ public final class DefaultAlarm implements Alarm {
219 215
220 public static class Builder { 216 public static class Builder {
221 217
222 - // Manadatory fields .. 218 + // Manadatory fields when constructing alarm ...
223 - private final AlarmId id; 219 + private AlarmId id;
224 private final DeviceId deviceId; 220 private final DeviceId deviceId;
225 private final String description; 221 private final String description;
226 - private final SeverityLevel severity; 222 + private SeverityLevel severity;
227 private final long timeRaised; 223 private final long timeRaised;
228 224
229 // Optional fields .. 225 // Optional fields ..
...@@ -236,8 +232,8 @@ public final class DefaultAlarm implements Alarm { ...@@ -236,8 +232,8 @@ public final class DefaultAlarm implements Alarm {
236 private String assignedUser = null; 232 private String assignedUser = null;
237 233
238 public Builder(final Alarm alarm) { 234 public Builder(final Alarm alarm) {
239 - this(alarm.id(), alarm.deviceId(), alarm.description(), alarm.severity(), alarm.timeRaised()); 235 + this(alarm.deviceId(), alarm.description(), alarm.severity(), alarm.timeRaised());
240 - this.source = AlarmEntityId.NONE; 236 + this.source = alarm.source();
241 this.timeUpdated = alarm.timeUpdated(); 237 this.timeUpdated = alarm.timeUpdated();
242 this.timeCleared = alarm.timeCleared(); 238 this.timeCleared = alarm.timeCleared();
243 this.isServiceAffecting = alarm.serviceAffecting(); 239 this.isServiceAffecting = alarm.serviceAffecting();
...@@ -247,10 +243,10 @@ public final class DefaultAlarm implements Alarm { ...@@ -247,10 +243,10 @@ public final class DefaultAlarm implements Alarm {
247 243
248 } 244 }
249 245
250 - public Builder(final AlarmId id, final DeviceId deviceId, 246 + public Builder(final DeviceId deviceId,
251 final String description, final SeverityLevel severity, final long timeRaised) { 247 final String description, final SeverityLevel severity, final long timeRaised) {
252 super(); 248 super();
253 - this.id = id; 249 + this.id = AlarmId.NONE;
254 this.deviceId = deviceId; 250 this.deviceId = deviceId;
255 this.description = description; 251 this.description = description;
256 this.severity = severity; 252 this.severity = severity;
...@@ -274,6 +270,17 @@ public final class DefaultAlarm implements Alarm { ...@@ -274,6 +270,17 @@ public final class DefaultAlarm implements Alarm {
274 return this; 270 return this;
275 } 271 }
276 272
273 + public Builder withId(final AlarmId id) {
274 + this.id = id;
275 + return this;
276 + }
277 +
278 + public Builder clear() {
279 + this.severity = SeverityLevel.CLEARED;
280 + final long now = System.currentTimeMillis();
281 + return withTimeCleared(now).withTimeUpdated(now);
282 + }
283 +
277 public Builder withServiceAffecting(final boolean isServiceAffecting) { 284 public Builder withServiceAffecting(final boolean isServiceAffecting) {
278 this.isServiceAffecting = isServiceAffecting; 285 this.isServiceAffecting = isServiceAffecting;
279 return this; 286 return this;
......
...@@ -16,19 +16,21 @@ ...@@ -16,19 +16,21 @@
16 package org.onosproject.incubator.net.faultmanagement.alarm; 16 package org.onosproject.incubator.net.faultmanagement.alarm;
17 17
18 import com.google.common.testing.EqualsTester; 18 import com.google.common.testing.EqualsTester;
19 +import static org.hamcrest.Matchers.containsString;
19 import org.junit.Test; 20 import org.junit.Test;
20 21
21 import static org.hamcrest.Matchers.is; 22 import static org.hamcrest.Matchers.is;
22 import static org.hamcrest.Matchers.not; 23 import static org.hamcrest.Matchers.not;
23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertThat; 25 import static org.junit.Assert.assertThat;
26 +import static org.junit.Assert.fail;
25 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; 27 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
26 28
27 /** 29 /**
28 - * This class tests the immutability, equality, and non-equality of 30 + * This class tests the immutability, equality, and non-equality of {@link AlarmId}.
29 - * {@link AlarmId}.
30 */ 31 */
31 public class AlarmIdTest { 32 public class AlarmIdTest {
33 +
32 private static final long ID_A = 1L; 34 private static final long ID_A = 1L;
33 private static final long ID_B = 2L; 35 private static final long ID_B = 2L;
34 private static final long ID_Z = 987654321L; 36 private static final long ID_Z = 987654321L;
...@@ -46,28 +48,27 @@ public class AlarmIdTest { ...@@ -46,28 +48,27 @@ public class AlarmIdTest {
46 */ 48 */
47 @Test 49 @Test
48 public void testEquality() { 50 public void testEquality() {
49 - final AlarmId id1 = new AlarmId(ID_A); 51 + final AlarmId id1 = AlarmId.alarmId(ID_A);
50 - final AlarmId id2 = new AlarmId(ID_A); 52 + final AlarmId id2 = AlarmId.alarmId(ID_A);
51 53
52 assertThat(id1, is(id2)); 54 assertThat(id1, is(id2));
53 } 55 }
54 56
55 -
56 /** 57 /**
57 * Tests non-equality of {@link AlarmId}. 58 * Tests non-equality of {@link AlarmId}.
58 */ 59 */
59 @Test 60 @Test
60 public void testNonEquality() { 61 public void testNonEquality() {
61 - final AlarmId id1 = new AlarmId(ID_A); 62 + final AlarmId id1 = AlarmId.alarmId(ID_A);
62 - final AlarmId id2 = new AlarmId(ID_B); 63 + final AlarmId id2 = AlarmId.alarmId(ID_B);
63 64
64 assertThat(id1, is(not(id2))); 65 assertThat(id1, is(not(id2)));
65 } 66 }
66 67
67 @Test 68 @Test
68 public void valueOf() { 69 public void valueOf() {
69 - final AlarmId id = new AlarmId(0xdeadbeefL); 70 + final AlarmId id = AlarmId.alarmId(0xdeadbeefL);
70 - assertEquals("incorrect valueOf", id, AlarmId.valueOf(0xdeadbeefL)); 71 + assertEquals("incorrect valueOf", id, AlarmId.alarmId(0xdeadbeefL));
71 } 72 }
72 73
73 /** 74 /**
...@@ -75,9 +76,9 @@ public class AlarmIdTest { ...@@ -75,9 +76,9 @@ public class AlarmIdTest {
75 */ 76 */
76 @Test 77 @Test
77 public void testEquals() { 78 public void testEquals() {
78 - final AlarmId id1 = new AlarmId(11111L); 79 + final AlarmId id1 = AlarmId.alarmId(11111L);
79 - final AlarmId sameAsId1 = new AlarmId(11111L); 80 + final AlarmId sameAsId1 = AlarmId.alarmId(11111L);
80 - final AlarmId id2 = new AlarmId(22222L); 81 + final AlarmId id2 = AlarmId.alarmId(22222L);
81 82
82 new EqualsTester() 83 new EqualsTester()
83 .addEqualityGroup(id1, sameAsId1) 84 .addEqualityGroup(id1, sameAsId1)
...@@ -90,9 +91,18 @@ public class AlarmIdTest { ...@@ -90,9 +91,18 @@ public class AlarmIdTest {
90 */ 91 */
91 @Test 92 @Test
92 public void testConstruction() { 93 public void testConstruction() {
93 - final AlarmId id1 = new AlarmId(ID_Z); 94 + final AlarmId id1 = AlarmId.alarmId(ID_Z);
94 assertEquals(id1.fingerprint(), ID_Z); 95 assertEquals(id1.fingerprint(), ID_Z);
95 96
96 // No default constructor so no need to test it ! 97 // No default constructor so no need to test it !
98 + assertEquals(0L, AlarmId.NONE.fingerprint());
99 + try {
100 + final AlarmId bad = AlarmId.alarmId(0L);
101 + fail("0 is a Reserved value but we created " + bad);
102 + } catch (IllegalArgumentException ex) {
103 + assertThat(ex.getMessage(),
104 + containsString("id must be non-zero"));
105 + }
106 +
97 } 107 }
98 } 108 }
......
...@@ -18,6 +18,7 @@ package org.onosproject.incubator.net.faultmanagement.alarm; ...@@ -18,6 +18,7 @@ package org.onosproject.incubator.net.faultmanagement.alarm;
18 import static org.hamcrest.MatcherAssert.assertThat; 18 import static org.hamcrest.MatcherAssert.assertThat;
19 import static org.hamcrest.Matchers.is; 19 import static org.hamcrest.Matchers.is;
20 import static org.hamcrest.Matchers.notNullValue; 20 import static org.hamcrest.Matchers.notNullValue;
21 +import static org.hamcrest.Matchers.greaterThan;
21 import org.junit.Test; 22 import org.junit.Test;
22 import static org.junit.Assert.*; 23 import static org.junit.Assert.*;
23 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; 24 import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
...@@ -35,13 +36,57 @@ public class DefaultAlarmTest { ...@@ -35,13 +36,57 @@ public class DefaultAlarmTest {
35 */ 36 */
36 @Test 37 @Test
37 public void testConstruction() { 38 public void testConstruction() {
38 - final String nameValue = "name3"; 39 + final DefaultAlarm a = generate();
39 - final DefaultAlarm a = new DefaultAlarm.Builder(AlarmId.valueOf(4),
40 - DeviceId.NONE, nameValue, Alarm.SeverityLevel.CLEARED, 3).build();
41 -
42 assertThat(a, is(notNullValue())); 40 assertThat(a, is(notNullValue()));
43 final DefaultAlarm b = new DefaultAlarm.Builder(a).build(); 41 final DefaultAlarm b = new DefaultAlarm.Builder(a).build();
44 -
45 assertEquals(a, b); 42 assertEquals(a, b);
46 } 43 }
44 +
45 + @Test
46 + public void testEquals() {
47 + final DefaultAlarm a = new DefaultAlarm.Builder(
48 + DeviceId.NONE, "desc", Alarm.SeverityLevel.MINOR, 3).build();
49 + final DefaultAlarm b = new DefaultAlarm.Builder(
50 + DeviceId.NONE, "desc", Alarm.SeverityLevel.MINOR, a.timeRaised() + 1).
51 + withId(ALARM_ID).withTimeUpdated(a.timeUpdated() + 1).build();
52 + assertEquals("id or timeRaised or timeUpdated may differ", a, b);
53 +
54 + assertNotEquals(a, new DefaultAlarm.Builder(a).withAcknowledged(!a.acknowledged()).build());
55 + assertNotEquals(a, new DefaultAlarm.Builder(a).withManuallyClearable(!a.manuallyClearable()).build());
56 + assertNotEquals(a, new DefaultAlarm.Builder(a).withServiceAffecting(!a.serviceAffecting()).build());
57 + assertNotEquals(a, new DefaultAlarm.Builder(a).withAssignedUser("Changed" + a.assignedUser()).build());
58 +
59 + }
60 +
61 + @Test
62 + public void testClear() {
63 + final DefaultAlarm active = generate();
64 + final DefaultAlarm cleared = new DefaultAlarm.Builder(active).clear().build();
65 + assertNotEquals(active, cleared);
66 + assertThat(cleared.timeRaised(), is(active.timeRaised()));
67 + assertThat(cleared.severity(), is(Alarm.SeverityLevel.CLEARED));
68 + assertThat(cleared.timeUpdated(), greaterThan(active.timeUpdated()));
69 + assertNotNull(cleared.timeCleared());
70 +
71 + }
72 +
73 + @Test
74 + public void testId() {
75 + final DefaultAlarm a = generate();
76 + assertThat(a.id(), is(AlarmId.NONE));
77 + final DefaultAlarm b = new DefaultAlarm.Builder(a).withId(ALARM_ID).build();
78 +
79 + assertEquals("id ignored in equals", a, b);
80 + assertNotEquals(ALARM_ID, a.id());
81 + assertEquals(ALARM_ID, b.id());
82 + assertEquals(ALARM_ENTITY_ID, b.source());
83 +
84 + }
85 + private static final AlarmEntityId ALARM_ENTITY_ID = AlarmEntityId.alarmEntityId("port:bar");
86 + private static final AlarmId ALARM_ID = AlarmId.alarmId(888L);
87 +
88 + private static DefaultAlarm generate() {
89 + return new DefaultAlarm.Builder(
90 + DeviceId.NONE, "desc", Alarm.SeverityLevel.MINOR, 3).forSource(ALARM_ENTITY_ID).build();
91 + }
47 } 92 }
......
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- 2 <!--
3 - ~ Copyright 2014 Open Networking Laboratory 3 +~ Copyright 2015 Open Networking Laboratory
4 - ~ 4 +~
5 - ~ Licensed under the Apache License, Version 2.0 (the "License"); 5 +~ Licensed under the Apache License, Version 2.0 (the "License");
6 - ~ you may not use this file except in compliance with the License. 6 +~ you may not use this file except in compliance with the License.
7 - ~ You may obtain a copy of the License at 7 +~ You may obtain a copy of the License at
8 - ~ 8 +~
9 - ~ http://www.apache.org/licenses/LICENSE-2.0 9 +~ http://www.apache.org/licenses/LICENSE-2.0
10 - ~ 10 +~
11 - ~ Unless required by applicable law or agreed to in writing, software 11 +~ Unless required by applicable law or agreed to in writing, software
12 - ~ distributed under the License is distributed on an "AS IS" BASIS, 12 +~ distributed under the License is distributed on an "AS IS" BASIS,
13 - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 - ~ See the License for the specific language governing permissions and 14 +~ See the License for the specific language governing permissions and
15 - ~ limitations under the License. 15 +~ limitations under the License.
16 - --> 16 +-->
17 <project xmlns="http://maven.apache.org/POM/4.0.0" 17 <project xmlns="http://maven.apache.org/POM/4.0.0"
18 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 18 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 19 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
...@@ -31,4 +31,136 @@ ...@@ -31,4 +31,136 @@
31 31
32 <description>ONOS SNMP protocol alarm provider</description> 32 <description>ONOS SNMP protocol alarm provider</description>
33 33
34 + <dependencies>
35 + <dependency>
36 + <groupId>com.btisystems</groupId>
37 + <artifactId>snmp-core</artifactId>
38 + <version>1.3-SNAPSHOT</version>
39 + </dependency>
40 +
41 + <dependency>
42 + <groupId>com.btisystems.mibbler.mibs</groupId>
43 + <artifactId>bti7000</artifactId>
44 + <version>1.0-SNAPSHOT</version>
45 + </dependency>
46 +
47 + <dependency>
48 + <groupId>com.btisystems.mibbler.mibs</groupId>
49 + <artifactId>net-snmp</artifactId>
50 + <version>1.0-SNAPSHOT</version>
51 + </dependency>
52 +
53 + <dependency>
54 + <groupId>org.osgi</groupId>
55 + <artifactId>org.osgi.compendium</artifactId>
56 + <version>5.0.0</version>
57 + <type>jar</type>
58 + </dependency>
59 +
60 + <dependency>
61 + <groupId>org.onosproject</groupId>
62 + <artifactId>onos-api</artifactId>
63 + <version>${project.version}</version>
64 + </dependency>
65 +
66 +
67 +
68 + <dependency>
69 + <groupId>org.onosproject</groupId>
70 + <artifactId>onlab-junit</artifactId>
71 + <scope>test</scope>
72 + </dependency>
73 +
74 + <dependency>
75 + <groupId>org.onosproject</groupId>
76 + <artifactId>onlab-osgi</artifactId>
77 + <version>${project.version}</version>
78 + <classifier>tests</classifier>
79 + <scope>test</scope>
80 + </dependency>
81 +
82 + <dependency>
83 + <groupId>org.onosproject</groupId>
84 + <artifactId>onos-api</artifactId>
85 + <version>${project.version}</version>
86 + <classifier>tests</classifier>
87 + <scope>test</scope>
88 + </dependency>
89 +
90 + <dependency>
91 + <groupId>junit</groupId>
92 + <artifactId>junit</artifactId>
93 + <version>4.11</version>
94 + <scope>test</scope>
95 + </dependency>
96 + <dependency>
97 + <groupId>org.hamcrest</groupId>
98 + <artifactId>hamcrest-core</artifactId>
99 + <version>1.3</version>
100 + <scope>test</scope>
101 + </dependency>
102 + <dependency>
103 + <groupId>org.hamcrest</groupId>
104 + <artifactId>hamcrest-library</artifactId>
105 + <version>1.3</version>
106 + <scope>test</scope>
107 + </dependency>
108 + <dependency>
109 + <groupId>org.easymock</groupId>
110 + <artifactId>easymock</artifactId>
111 + <scope>test</scope>
112 + </dependency>
113 + </dependencies>
114 +
115 + <build>
116 + <plugins>
117 + <plugin>
118 + <groupId>org.apache.maven.plugins</groupId>
119 + <artifactId>maven-shade-plugin</artifactId>
120 + <version>2.3</version>
121 + <configuration>
122 + <filters>
123 + <filter>
124 + <artifact>com.btisystems:snmp-core</artifact>
125 + <excludes>
126 + <exclude>**</exclude>
127 + </excludes>
128 + </filter>
129 + <filter>
130 + <artifact>com.btisystems.mibbler.mibs:bti7000</artifact>
131 + <excludes>
132 + <exclude>**</exclude>
133 + </excludes>
134 + </filter>
135 + <filter>
136 + <artifact>com.btisystems.mibbler.mibs:net-snmp</artifact>
137 + <excludes>
138 + <exclude>**</exclude>
139 + </excludes>
140 + </filter>
141 + </filters>
142 + </configuration>
143 + <executions>
144 + <execution>
145 + <phase>package</phase>
146 + <goals>
147 + <goal>shade</goal>
148 + </goals>
149 + </execution>
150 + </executions>
151 + </plugin>
152 + <plugin>
153 + <groupId>org.apache.felix</groupId>
154 + <artifactId>maven-scr-plugin</artifactId>
155 + </plugin>
156 + <plugin>
157 + <groupId>org.apache.felix</groupId>
158 + <artifactId>maven-bundle-plugin</artifactId>
159 + </plugin>
160 + <plugin>
161 + <groupId>org.onosproject</groupId>
162 + <artifactId>onos-maven-plugin</artifactId>
163 + </plugin>
164 + </plugins>
165 + </build>
34 </project> 166 </project>
......
1 +/*
2 + *
3 + * Licensed under the Apache License, Version 2.0 (the "License");
4 + * you may not use this file except in compliance with the License.
5 + * You may obtain a copy of the License at
6 + *
7 + * http://www.apache.org/licenses/LICENSE-2.0
8 + *
9 + * Unless required by applicable law or agreed to in writing, software
10 + * distributed under the License is distributed on an "AS IS" BASIS,
11 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 + * See the License for the specific language governing permissions and
13 + * limitations under the License.
14 + */
15 +package org.onosproject.provider.snmp.alarm.impl;
16 +
17 +import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.I_Device;
18 +import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0._OidRegistry;
19 +import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.btisystems.btiproducts.bti7000.objects.conditions.ActAlarmTable;
20 +import com.btisystems.mibbler.mibs.bti7000.interfaces.btisystems.btiproducts.bti7000.objects.conditions.IActAlarmTable;
21 +import com.btisystems.pronx.ems.core.model.ClassRegistry;
22 +import com.btisystems.pronx.ems.core.model.IClassRegistry;
23 +import com.btisystems.pronx.ems.core.model.NetworkDevice;
24 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
25 +import java.io.IOException;
26 +import java.util.Arrays;
27 +import java.util.Calendar;
28 +import java.util.Collection;
29 +import java.util.Date;
30 +import java.util.GregorianCalendar;
31 +import java.util.HashSet;
32 +import java.util.Set;
33 +import java.util.TimeZone;
34 +import org.apache.commons.lang.StringUtils;
35 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
36 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
37 +import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
38 +import org.onosproject.net.DeviceId;
39 +import org.slf4j.Logger;
40 +import static org.slf4j.LoggerFactory.getLogger;
41 +import org.snmp4j.smi.OID;
42 +import org.snmp4j.smi.OctetString;
43 +
44 +/**
45 + * BTI 7000 specific implementation to provide a list of current alarms.
46 + */
47 +public class Bti7000SnmpAlarmProvider implements SnmpDeviceAlarmProvider {
48 + private final Logger log = getLogger(getClass());
49 + protected static final IClassRegistry CLASS_REGISTRY = new ClassRegistry(_OidRegistry.oidRegistry, I_Device.class);
50 +
51 + static final int ALARM_SEVERITY_MINOR = 2;
52 + static final int ALARM_SEVERITY_MAJOR = 3;
53 + static final int ALARM_SEVERITY_CRITICAL = 4;
54 +
55 + @Override
56 + public Collection<Alarm> getAlarms(ISnmpSession session, DeviceId deviceID) {
57 + log.info("Getting alarms for BTI 7000 device at {}", deviceID);
58 + Set<Alarm> alarms = new HashSet<>();
59 + NetworkDevice networkDevice = new NetworkDevice(CLASS_REGISTRY,
60 + session.getAddress().getHostAddress());
61 +
62 + try {
63 + session.walkDevice(networkDevice, Arrays.asList(
64 + new OID[]{CLASS_REGISTRY.getClassToOidMap().get(ActAlarmTable.class)}));
65 +
66 + IActAlarmTable deviceAlarms = (IActAlarmTable) networkDevice.getRootObject()
67 + .getEntity(CLASS_REGISTRY.getClassToOidMap().get(ActAlarmTable.class));
68 + if ((deviceAlarms != null) && (deviceAlarms.getActAlarmEntry() != null)
69 + && (!deviceAlarms.getActAlarmEntry().isEmpty())) {
70 +
71 + deviceAlarms.getActAlarmEntry().values().stream().forEach((alarm) -> {
72 + DefaultAlarm.Builder alarmBuilder = new DefaultAlarm.Builder(
73 + deviceID, alarm.getActAlarmDescription(),
74 + mapAlarmSeverity(alarm.getActAlarmSeverity()),
75 + getLocalDateAndTime(alarm.getActAlarmDateAndTime(), null, null).getTime())
76 + .forSource(AlarmEntityId.alarmEntityId("other:" + alarm.getActAlarmInstanceIdx()));
77 + alarms.add(alarmBuilder.build());
78 + });
79 +
80 + }
81 + log.info("Conditions retrieved: {}", deviceAlarms);
82 +
83 + } catch (IOException ex) {
84 + log.error("Error reading alarms for device {}.", deviceID, ex);
85 + }
86 +
87 + return alarms;
88 + }
89 +
90 + private Alarm.SeverityLevel mapAlarmSeverity(int intAlarmSeverity) {
91 + Alarm.SeverityLevel mappedSeverity;
92 + switch (intAlarmSeverity) {
93 + case ALARM_SEVERITY_MINOR:
94 + mappedSeverity = Alarm.SeverityLevel.MINOR;
95 + break;
96 + case ALARM_SEVERITY_MAJOR:
97 + mappedSeverity = Alarm.SeverityLevel.MAJOR;
98 + break;
99 + case ALARM_SEVERITY_CRITICAL:
100 + mappedSeverity = Alarm.SeverityLevel.CRITICAL;
101 + break;
102 + default:
103 + mappedSeverity = Alarm.SeverityLevel.MINOR;
104 + log.warn("Unexpected alarm severity: {}", intAlarmSeverity);
105 + }
106 + return mappedSeverity;
107 + }
108 + /**
109 + * Converts an SNMP string representation into a {@link Date} object,
110 + * and applies time zone conversion to provide the time on the local machine, ie PSM server.
111 + *
112 + * @param actAlarmDateAndTime MIB-II DateAndTime formatted. May optionally contain
113 + * a timezone offset in 3 extra bytes
114 + * @param sysInfoTimeZone Must be supplied if actAlarmDateAndTime is just local time (with no timezone)
115 + * @param swVersion Must be supplied if actAlarmDateAndTime is just local time (with no timezone)
116 + * @return adjusted {@link Date} or a simple conversion if other fields are null.
117 + */
118 + public static Date getLocalDateAndTime(String actAlarmDateAndTime, String sysInfoTimeZone,
119 + String swVersion) {
120 + if (StringUtils.isBlank(actAlarmDateAndTime)) {
121 + return null;
122 + }
123 +
124 + GregorianCalendar decodedDateAndTimeCal = btiMakeCalendar(OctetString.fromHexString(actAlarmDateAndTime));
125 + if ((sysInfoTimeZone == null) || (swVersion == null)) {
126 + return decodedDateAndTimeCal.getTime();
127 + }
128 +
129 + TimeZone javaTimeZone = getTimeZone();
130 + decodedDateAndTimeCal.setTimeZone(javaTimeZone);
131 +
132 + GregorianCalendar localTime = new GregorianCalendar();
133 + localTime.setTimeInMillis(decodedDateAndTimeCal.getTimeInMillis());
134 +
135 + return localTime.getTime();
136 + }
137 +
138 + /**
139 + * This method is similar to SNMP4J approach with some fixes for the 11-bytes version (ie the one with timezone
140 + * offset).
141 + *
142 + * For original makeCalendar refer @see http://www.snmp4j.org/agent/doc/org/snmp4j/agent/mo/snmp/DateAndTime.html
143 + *
144 + * Creates a <code>GregorianCalendar</code> from a properly formatted SNMP4J DateAndTime <code>OctetString</code>.
145 + *
146 + * @param dateAndTimeValue an OctetString conforming to the DateAndTime TC.
147 + * @return the corresponding <code>GregorianCalendar</code> instance.
148 + *
149 + */
150 + public static GregorianCalendar btiMakeCalendar(OctetString dateAndTimeValue) {
151 + int year = (dateAndTimeValue.get(0) & 0xFF) * 256
152 + + (dateAndTimeValue.get(1) & 0xFF);
153 + int month = (dateAndTimeValue.get(2) & 0xFF);
154 + int date = (dateAndTimeValue.get(3) & 0xFF);
155 + int hour = (dateAndTimeValue.get(4) & 0xFF);
156 + int minute = (dateAndTimeValue.get(5) & 0xFF);
157 + int second = (dateAndTimeValue.get(6) & 0xFF);
158 + int deci = (dateAndTimeValue.get(7) & 0xFF);
159 + GregorianCalendar gc =
160 + new GregorianCalendar(year, month - 1, date, hour, minute, second);
161 + gc.set(Calendar.MILLISECOND, deci * 100);
162 +
163 + if (dateAndTimeValue.length() == 11) {
164 + char directionOfOffset = (char) dateAndTimeValue.get(8);
165 + int hoursOffset = directionOfOffset == '+'
166 + ? dateAndTimeValue.get(9) : -dateAndTimeValue.get(9);
167 + org.joda.time.DateTimeZone offset =
168 + org.joda.time.DateTimeZone.forOffsetHoursMinutes(hoursOffset, dateAndTimeValue.get(10));
169 + org.joda.time.DateTime dt =
170 + new org.joda.time.DateTime(year, month, date, hour, minute, second, offset);
171 + return dt.toGregorianCalendar();
172 + }
173 + return gc;
174 + }
175 +
176 + private static TimeZone getTimeZone() {
177 + return Calendar.getInstance().getTimeZone();
178 + }
179 +}
1 +/*
2 + *
3 + * Licensed under the Apache License, Version 2.0 (the "License");
4 + * you may not use this file except in compliance with the License.
5 + * You may obtain a copy of the License at
6 + *
7 + * http://www.apache.org/licenses/LICENSE-2.0
8 + *
9 + * Unless required by applicable law or agreed to in writing, software
10 + * distributed under the License is distributed on an "AS IS" BASIS,
11 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 + * See the License for the specific language governing permissions and
13 + * limitations under the License.
14 + */
15 +package org.onosproject.provider.snmp.alarm.impl;
16 +
17 +import com.btisystems.mibbler.mibs.netsnmp.netsnmp.I_Device;
18 +import com.btisystems.mibbler.mibs.netsnmp.netsnmp._OidRegistry;
19 +import com.btisystems.mibbler.mibs.netsnmp.netsnmp.mib_2.interfaces.IfTable;
20 +import com.btisystems.pronx.ems.core.model.ClassRegistry;
21 +import com.btisystems.pronx.ems.core.model.IClassRegistry;
22 +import com.btisystems.pronx.ems.core.model.NetworkDevice;
23 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
24 +import java.io.IOException;
25 +import java.util.Arrays;
26 +import java.util.Collection;
27 +import java.util.HashSet;
28 +import java.util.Set;
29 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
30 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEntityId;
31 +import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
32 +import org.onosproject.net.DeviceId;
33 +import org.slf4j.Logger;
34 +import static org.slf4j.LoggerFactory.getLogger;
35 +import org.snmp4j.smi.OID;
36 +
37 +/**
38 + * Net SNMP specific implementation to provide a list of current alarms.
39 + */
40 +public class NetSnmpAlarmProvider implements SnmpDeviceAlarmProvider {
41 + private final Logger log = getLogger(getClass());
42 + protected static final IClassRegistry CLASS_REGISTRY =
43 + new ClassRegistry(_OidRegistry.oidRegistry, I_Device.class);
44 + @Override
45 + public Collection<Alarm> getAlarms(ISnmpSession session, DeviceId deviceId) {
46 + Set<Alarm> alarms = new HashSet<>();
47 +
48 + NetworkDevice networkDevice = new NetworkDevice(CLASS_REGISTRY,
49 + session.getAddress().getHostAddress());
50 + try {
51 + session.walkDevice(networkDevice, Arrays.asList(new OID[]{
52 + CLASS_REGISTRY.getClassToOidMap().get(IfTable.class)}));
53 +
54 + IfTable interfaceTable = (IfTable) networkDevice.getRootObject()
55 + .getEntity(CLASS_REGISTRY.getClassToOidMap().get(IfTable.class));
56 + if (interfaceTable != null) {
57 + interfaceTable.getEntries().values().stream().forEach((ifEntry) -> {
58 + //TODO will raise alarm for each interface as a demo.
59 + // if (ifEntry.getIfAdminStatus() == 1 && ifEntry.getIfOperStatus() == 2){
60 + alarms.add(new DefaultAlarm.Builder(deviceId, "Link Down.",
61 + Alarm.SeverityLevel.CRITICAL, System.currentTimeMillis())
62 + .forSource(AlarmEntityId.alarmEntityId("port:" + ifEntry.getIfDescr())).build());
63 + // }
64 + log.info("Interface: " + ifEntry);
65 + });
66 + }
67 + } catch (IOException ex) {
68 + log.error("Error reading alarms for device {}.", deviceId, ex);
69 + }
70 + return alarms;
71 + }
72 +}
1 -/*
2 - * Copyright 2014-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 -package org.onosproject.provider.snmp.alarm.impl;
17 -
18 -import org.apache.felix.scr.annotations.Component;
19 -import org.onosproject.net.DeviceId;
20 -import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider;
21 -import org.onosproject.net.provider.AbstractProvider;
22 -import org.onosproject.net.provider.ProviderId;
23 -import org.slf4j.Logger;
24 -
25 -import static org.slf4j.LoggerFactory.getLogger;
26 -
27 -/**
28 - * Provider which uses an SNMP controller to detect network device alarms. The class leverages functionality from
29 - *
30 - * @see <a href="https://github.com/btisystems/snmp-core">https://github.com/btisystems/snmp-core</a>
31 - * @see <a href="https://github.com/btisystems/mibbler">https://github.com/btisystems/mibbler</a>
32 - */
33 -@Component(immediate = true)
34 -public class SNMPAlarmProvider extends AbstractProvider implements AlarmProvider {
35 -
36 - private static final Logger LOG = getLogger(SNMPAlarmProvider.class);
37 -
38 - /**
39 - * Creates a SNMP alarm provider, dummy class provided as template, tbd later.
40 - */
41 - public SNMPAlarmProvider() {
42 - super(new ProviderId("snmp", "org.onosproject.provider.alarm"));
43 - }
44 -
45 - @Override
46 - public void triggerProbe(DeviceId deviceId) {
47 -
48 - // TODO in shout term should this just be synchronous and return result?
49 - LOG.info("Run a SNMP discovery for device at {} when done invoke on AlarmProviderService", deviceId);
50 -
51 - // TODO Look up AlarmProviderService
52 - // TODO Decide threading
53 - // TODO Decide shouldn't it be generic not alarm-specific ? Its user responsible for passing in OID list ?
54 - // Same for its callack AlarmProviderService ?
55 - }
56 -
57 -}
1 +/*
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 +package org.onosproject.provider.snmp.alarm.impl;
17 +
18 +import com.btisystems.pronx.ems.core.snmp.DefaultSnmpConfigurationFactory;
19 +import com.btisystems.pronx.ems.core.snmp.ISnmpConfiguration;
20 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
21 +import com.btisystems.pronx.ems.core.snmp.ISnmpSessionFactory;
22 +import com.btisystems.pronx.ems.core.snmp.SnmpSessionFactory;
23 +import com.btisystems.pronx.ems.core.snmp.V2cSnmpConfiguration;
24 +import static com.google.common.base.Preconditions.checkNotNull;
25 +import com.google.common.collect.Sets;
26 +import java.io.IOException;
27 +import static org.slf4j.LoggerFactory.getLogger;
28 +
29 +import java.util.Collection;
30 +import java.util.HashMap;
31 +import java.util.HashSet;
32 +import java.util.Map;
33 +import java.util.Set;
34 +import java.util.concurrent.ExecutorService;
35 +import java.util.concurrent.Executors;
36 +
37 +import org.apache.felix.scr.annotations.Activate;
38 +import org.apache.felix.scr.annotations.Component;
39 +import org.apache.felix.scr.annotations.Deactivate;
40 +import org.apache.felix.scr.annotations.Modified;
41 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
42 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEvent;
43 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmListener;
44 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProvider;
45 +
46 +import org.onosproject.net.DeviceId;
47 +import org.onosproject.net.provider.AbstractProvider;
48 +import org.onosproject.net.provider.ProviderId;
49 +import org.osgi.service.component.ComponentContext;
50 +import org.slf4j.Logger;
51 +import org.apache.felix.scr.annotations.Reference;
52 +import org.apache.felix.scr.annotations.ReferenceCardinality;
53 +import static org.onlab.util.Tools.groupedThreads;
54 +import org.onosproject.core.ApplicationId;
55 +import org.onosproject.core.CoreService;
56 +import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
57 +import org.onosproject.net.device.DeviceEvent;
58 +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
59 +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
60 +import org.onosproject.net.device.DeviceListener;
61 +import org.onosproject.net.device.DeviceService;
62 +
63 +/**
64 + * SNMP alarms provider.
65 + */
66 +@Component(immediate = true)
67 +public 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 +}
1 +/*
2 + * Licensed under the Apache License, Version 2.0 (the "License");
3 + * you may not use this file except in compliance with the License.
4 + * You may obtain a copy of the License at
5 + *
6 + * http://www.apache.org/licenses/LICENSE-2.0
7 + *
8 + * Unless required by applicable law or agreed to in writing, software
9 + * distributed under the License is distributed on an "AS IS" BASIS,
10 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 + * See the License for the specific language governing permissions and
12 + * limitations under the License.
13 + */
14 +package org.onosproject.provider.snmp.alarm.impl;
15 +
16 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
17 +import java.util.Collection;
18 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
19 +import org.onosproject.net.DeviceId;
20 +
21 +public interface SnmpDeviceAlarmProvider {
22 + /**
23 + * Implemented by device specific implementations which query the current
24 + * alarms from a device.
25 + * @param snmpSession SNMP Session
26 + * @param deviceId device identifier
27 + * @return device alarms
28 + */
29 + Collection<Alarm> getAlarms(ISnmpSession snmpSession, DeviceId deviceId);
30 +}
1 /* 1 /*
2 +<<<<<<< HEAD
3 + * Copyright 2015 Open Networking Laboratory
4 +=======
2 * Copyright 2014 Open Networking Laboratory 5 * Copyright 2014 Open Networking Laboratory
6 +>>>>>>> master
3 * 7 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 9 * you may not use this file except in compliance with the License.
...@@ -15,6 +19,6 @@ ...@@ -15,6 +19,6 @@
15 */ 19 */
16 20
17 /** 21 /**
18 - * Provider that uses SNMP as a means of discovering alarms on devices. 22 + * Provider that will support SNMP alarm discoveries.
19 */ 23 */
20 package org.onosproject.provider.snmp.alarm.impl; 24 package org.onosproject.provider.snmp.alarm.impl;
......
1 +/*
2 + * Licensed under the Apache License, Version 2.0 (the "License");
3 + * you may not use this file except in compliance with the License.
4 + * You may obtain a copy of the License at
5 + *
6 + * http://www.apache.org/licenses/LICENSE-2.0
7 + *
8 + * Unless required by applicable law or agreed to in writing, software
9 + * distributed under the License is distributed on an "AS IS" BASIS,
10 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 + * See the License for the specific language governing permissions and
12 + * limitations under the License.
13 + */
14 +package org.onosproject.provider.snmp.alarm.impl;
15 +
16 +import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.btisystems.btiproducts.bti7000.objects.conditions.ActAlarmTable;
17 +import com.btisystems.mibbler.mibs.bti7000.interfaces.btisystems.btiproducts.bti7000.objects.conditions.actalarmtable.IActAlarmEntry;
18 +import com.btisystems.pronx.ems.core.model.NetworkDevice;
19 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
20 +import java.io.IOException;
21 +import java.net.InetAddress;
22 +import java.net.UnknownHostException;
23 +import java.util.Arrays;
24 +import java.util.Collection;
25 +import org.easymock.Capture;
26 +import static org.easymock.EasyMock.capture;
27 +import static org.easymock.EasyMock.createMock;
28 +import static org.easymock.EasyMock.eq;
29 +import static org.easymock.EasyMock.expect;
30 +import static org.easymock.EasyMock.isA;
31 +import static org.easymock.EasyMock.replay;
32 +import static org.easymock.EasyMock.verify;
33 +import org.junit.Before;
34 +import org.junit.Test;
35 +import static org.junit.Assert.*;
36 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
37 +import org.onosproject.net.DeviceId;
38 +import org.snmp4j.smi.OID;
39 +
40 +
41 +public class Bti7000SnmpAlarmProviderTest {
42 + private Bti7000SnmpAlarmProvider alarmProvider;
43 + private ISnmpSession mockSession;
44 + private ActAlarmTable alarmsTable;
45 +
46 + public Bti7000SnmpAlarmProviderTest() {
47 + }
48 +
49 + @Before
50 + public void setUp() {
51 + mockSession = createMock(ISnmpSession.class);
52 +
53 + alarmProvider = new Bti7000SnmpAlarmProvider();
54 + }
55 +
56 + @Test
57 + public void shouldWalkDevice() throws UnknownHostException, IOException {
58 + expect(mockSession.getAddress()).andReturn(InetAddress.getLoopbackAddress());
59 + expect(mockSession.walkDevice(isA(NetworkDevice.class),
60 + eq(Arrays.asList(new OID[]{
61 + Bti7000SnmpAlarmProvider.CLASS_REGISTRY.getClassToOidMap().get(ActAlarmTable.class)}))))
62 + .andReturn(null);
63 +
64 + replay(mockSession);
65 +
66 + assertNotNull(alarmProvider.getAlarms(mockSession, DeviceId.deviceId("snmp:1.1.1.1")));
67 +
68 + verify(mockSession);
69 + }
70 +
71 + @Test
72 + public void shouldFindAlarms() throws UnknownHostException, IOException {
73 + alarmsTable = new ActAlarmTable();
74 + alarmsTable.createEntry("14.1.3.6.1.4.1.18070.2.2.2.2.20.0.1.13.1.3.6.1.4.1."
75 + + "18070.2.2.1.4.14.1.7.49.46.55.46.50.46.53");
76 + IActAlarmEntry entry = alarmsTable.getEntries().values().iterator().next();
77 + entry.setActAlarmDescription("XFP Missing.");
78 + entry.setActAlarmDateAndTime("07:df:0c:01:03:0d:30:00");
79 + entry.setActAlarmSeverity(1);
80 +
81 + Capture<NetworkDevice> networkDeviceCapture = new Capture<>();
82 +
83 + expect(mockSession.getAddress()).andReturn(InetAddress.getLoopbackAddress());
84 + expect(mockSession.walkDevice(capture(networkDeviceCapture),
85 + eq(Arrays.asList(new OID[]{
86 + Bti7000SnmpAlarmProvider.CLASS_REGISTRY.getClassToOidMap().get(ActAlarmTable.class)}))))
87 + .andAnswer(() -> {
88 + networkDeviceCapture.getValue().getRootObject().setObject(alarmsTable);
89 + return null;
90 + });
91 +
92 + replay(mockSession);
93 +
94 + Collection<Alarm> alarms = alarmProvider.getAlarms(mockSession, DeviceId.deviceId("snmp:1.1.1.1"));
95 + assertEquals(1, alarms.size());
96 + assertEquals("XFP Missing.", alarms.iterator().next().description());
97 + verify(mockSession);
98 + }
99 +
100 + @Test
101 + public void shouldHandleException() throws UnknownHostException, IOException {
102 + expect(mockSession.getAddress()).andReturn(InetAddress.getLoopbackAddress());
103 + expect(mockSession.walkDevice(isA(NetworkDevice.class),
104 + eq(Arrays.asList(new OID[]{
105 + Bti7000SnmpAlarmProvider.CLASS_REGISTRY.getClassToOidMap().get(ActAlarmTable.class)}))))
106 + .andThrow(new IOException());
107 +
108 + replay(mockSession);
109 +
110 + assertNotNull(alarmProvider.getAlarms(mockSession, DeviceId.deviceId("snmp:1.1.1.1")));
111 +
112 + verify(mockSession);
113 + }
114 +
115 +}
1 +/*
2 + * Licensed under the Apache License, Version 2.0 (the "License");
3 + * you may not use this file except in compliance with the License.
4 + * You may obtain a copy of the License at
5 + *
6 + * http://www.apache.org/licenses/LICENSE-2.0
7 + *
8 + * Unless required by applicable law or agreed to in writing, software
9 + * distributed under the License is distributed on an "AS IS" BASIS,
10 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 + * See the License for the specific language governing permissions and
12 + * limitations under the License.
13 + */
14 +package org.onosproject.provider.snmp.alarm.impl;
15 +
16 +import com.btisystems.mibbler.mibs.netsnmp.interfaces.mib_2.interfaces.iftable.IIfEntry;
17 +import com.btisystems.mibbler.mibs.netsnmp.netsnmp.mib_2.interfaces.IfTable;
18 +import com.btisystems.pronx.ems.core.model.NetworkDevice;
19 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
20 +import java.io.IOException;
21 +import java.net.InetAddress;
22 +import java.net.UnknownHostException;
23 +import java.util.Arrays;
24 +import java.util.Collection;
25 +import org.easymock.Capture;
26 +import static org.easymock.EasyMock.capture;
27 +import static org.easymock.EasyMock.createMock;
28 +import static org.easymock.EasyMock.eq;
29 +import static org.easymock.EasyMock.expect;
30 +import static org.easymock.EasyMock.isA;
31 +import static org.easymock.EasyMock.replay;
32 +import static org.easymock.EasyMock.verify;
33 +import org.junit.Before;
34 +import org.junit.Test;
35 +import static org.junit.Assert.*;
36 +import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
37 +import org.onosproject.net.DeviceId;
38 +import org.snmp4j.smi.OID;
39 +
40 +
41 +public class NetSnmpSnmpAlarmProviderTest {
42 + private NetSnmpAlarmProvider alarmProvider;
43 + private ISnmpSession mockSession;
44 + private IfTable interfaceTable;
45 +
46 + public NetSnmpSnmpAlarmProviderTest() {
47 + }
48 +
49 + @Before
50 + public void setUp() {
51 + mockSession = createMock(ISnmpSession.class);
52 +
53 + alarmProvider = new NetSnmpAlarmProvider();
54 + }
55 +
56 + @Test
57 + public void shouldWalkDevice() throws UnknownHostException, IOException {
58 + expect(mockSession.getAddress()).andReturn(InetAddress.getLoopbackAddress());
59 + expect(mockSession.walkDevice(isA(NetworkDevice.class),
60 + eq(Arrays.asList(new OID[]{
61 + NetSnmpAlarmProvider.CLASS_REGISTRY.getClassToOidMap().get(IfTable.class)}))))
62 + .andReturn(null);
63 +
64 + replay(mockSession);
65 +
66 + assertNotNull(alarmProvider.getAlarms(mockSession, DeviceId.deviceId("snmp:1.1.1.1")));
67 +
68 + verify(mockSession);
69 + }
70 +
71 + @Test
72 + public void shouldFindAlarms() throws UnknownHostException, IOException {
73 + interfaceTable = new IfTable();
74 + interfaceTable.createEntry("1");
75 + IIfEntry entry = interfaceTable.getEntry("1");
76 + entry.setIfDescr("eth1");
77 + entry.setIfAdminStatus(1);
78 + entry.setIfOperStatus(2);
79 +
80 + Capture<NetworkDevice> networkDeviceCapture = new Capture<>();
81 +
82 + expect(mockSession.getAddress()).andReturn(InetAddress.getLoopbackAddress());
83 + expect(mockSession.walkDevice(capture(networkDeviceCapture),
84 + eq(Arrays.asList(new OID[]{
85 + NetSnmpAlarmProvider.CLASS_REGISTRY.getClassToOidMap().get(IfTable.class)}))))
86 + .andAnswer(() -> {
87 + networkDeviceCapture.getValue().getRootObject().setObject(interfaceTable);
88 + return null;
89 + });
90 +
91 + replay(mockSession);
92 +
93 + Collection<Alarm> alarms = alarmProvider.getAlarms(mockSession, DeviceId.deviceId("snmp:1.1.1.1"));
94 + assertEquals(1, alarms.size());
95 + assertEquals("Link Down.", alarms.iterator().next().description());
96 + verify(mockSession);
97 + }
98 +
99 + @Test
100 + public void shouldHandleException() throws UnknownHostException, IOException {
101 + expect(mockSession.getAddress()).andReturn(InetAddress.getLoopbackAddress());
102 + expect(mockSession.walkDevice(isA(NetworkDevice.class),
103 + eq(Arrays.asList(new OID[]{
104 + NetSnmpAlarmProvider.CLASS_REGISTRY.getClassToOidMap().get(IfTable.class)}))))
105 + .andThrow(new IOException());
106 +
107 + replay(mockSession);
108 +
109 + assertNotNull(alarmProvider.getAlarms(mockSession, DeviceId.deviceId("snmp:1.1.1.1")));
110 +
111 + verify(mockSession);
112 + }
113 +
114 +}
1 +/*
2 + * Licensed under the Apache License, Version 2.0 (the "License");
3 + * you may not use this file except in compliance with the License.
4 + * You may obtain a copy of the License at
5 + *
6 + * http://www.apache.org/licenses/LICENSE-2.0
7 + *
8 + * Unless required by applicable law or agreed to in writing, software
9 + * distributed under the License is distributed on an "AS IS" BASIS,
10 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 + * See the License for the specific language governing permissions and
12 + * limitations under the License.
13 + */
14 +package org.onosproject.provider.snmp.alarm.impl;
15 +
16 +import com.btisystems.pronx.ems.core.snmp.ISnmpConfiguration;
17 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
18 +import com.btisystems.pronx.ems.core.snmp.ISnmpSessionFactory;
19 +import java.io.IOException;
20 +import java.util.HashSet;
21 +import org.easymock.EasyMock;
22 +import static org.easymock.EasyMock.expect;
23 +import static org.easymock.EasyMock.replay;
24 +import static org.easymock.EasyMock.verify;
25 +import org.junit.Assert;
26 +import org.junit.Before;
27 +import org.junit.Test;
28 +import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEvent;
29 +import org.onosproject.net.DeviceId;
30 +
31 +public class SnmpDeviceAlarmProviderTest {
32 + private SnmpAlarmProviderService alarmProvider;
33 + private ISnmpSessionFactory mockSessionFactory;
34 + private ISnmpSession mockSession;
35 + private SnmpDeviceAlarmProvider mockProvider;
36 + private AlarmEvent alarmEvent;
37 +
38 + public SnmpDeviceAlarmProviderTest() {}
39 +
40 + @Before
41 + public void setUp() {
42 + mockSessionFactory = EasyMock.createMock(ISnmpSessionFactory.class);
43 + mockSession = EasyMock.createMock(ISnmpSession.class);
44 + mockProvider = EasyMock.createMock(SnmpDeviceAlarmProvider.class);
45 +
46 + alarmProvider = new SnmpAlarmProviderService() {
47 + @Override
48 + protected ISnmpSessionFactory getSessionFactory() {
49 + return mockSessionFactory;
50 + }
51 + };
52 +
53 + alarmProvider.addAlarmListener((AlarmEvent event) -> {
54 + alarmEvent = event;
55 + });
56 + }
57 +
58 + @Test
59 + public void shouldPopulateAlarmsForNetSnmp() throws IOException {
60 + alarmProvider.providers.put("1.2.3.4", mockProvider);
61 + expect(mockSessionFactory.createSession(EasyMock.isA(ISnmpConfiguration.class),
62 + EasyMock.eq("1.1.1.1"))).andReturn(mockSession);
63 + expect(mockSession.identifyDevice()).andReturn("1.2.3.4");
64 + expect(mockProvider.getAlarms(mockSession, DeviceId.deviceId("snmp:1.1.1.1:161")))
65 + .andReturn(new HashSet<>());
66 +
67 + mockSession.close();
68 + EasyMock.expectLastCall().once();
69 +
70 + replay(mockSessionFactory, mockSession, mockProvider);
71 +
72 + alarmProvider.triggerProbe(DeviceId.deviceId("snmp:1.1.1.1:161"));
73 +
74 + verify(mockSessionFactory, mockSession, mockProvider);
75 + Assert.assertNotNull(alarmEvent);
76 + }
77 +
78 +}
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<app name="org.onosproject.snmp" origin="BTI Systems" version="${project.version}"
18 + featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
19 + features="${project.artifactId}">
20 + <description>${project.description}</description>
21 + <artifact>mvn:${project.groupId}/onos-snmp-provider-device/${project.version}</artifact>
22 + <artifact>mvn:${project.groupId}/onos-snmp-provider-alarm/${project.version}</artifact>
23 +</app>
1 +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
18 + <feature name="${project.artifactId}" version="${project.version}"
19 + description="${project.description}">
20 + <feature>onos-api</feature>
21 + <bundle>mvn:io.netty/netty/3.9.2.Final</bundle>
22 + <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.snmp4j/2.3.4_1</bundle>
23 + <bundle>mvn:${project.groupId}/onos-snmp-provider-device/${project.version}</bundle>
24 + <bundle>mvn:com.btisystems/snmp-core/1.3-SNAPSHOT</bundle>
25 + <bundle>mvn:com.btisystems.mibbler.mibs/bti7000/1.0-SNAPSHOT</bundle>
26 + <bundle>mvn:com.btisystems.mibbler.mibs/net-snmp/1.0-SNAPSHOT</bundle>
27 + </feature>
28 +</features>
29 +
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
20 + <modelVersion>4.0.0</modelVersion>
21 +
22 + <parent>
23 + <groupId>org.onosproject</groupId>
24 + <artifactId>onos-snmp-providers</artifactId>
25 + <version>1.4.0-SNAPSHOT</version>
26 + <relativePath>../pom.xml</relativePath>
27 + </parent>
28 +
29 + <artifactId>onos-snmp-app</artifactId>
30 + <packaging>pom</packaging>
31 +
32 + <description>SNMP protocol southbound providers</description>
33 +
34 + <dependencies>
35 + <dependency>
36 + <groupId>org.onosproject</groupId>
37 + <artifactId>onos-snmp-provider-device</artifactId>
38 + <version>${project.version}</version>
39 + </dependency>
40 + <dependency>
41 + <groupId>org.onosproject</groupId>
42 + <artifactId>onos-snmp-provider-alarm</artifactId>
43 + <version>${project.version}</version>
44 + </dependency>
45 + </dependencies>
46 +
47 +</project>
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 +-->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
20 + <modelVersion>4.0.0</modelVersion>
21 +
22 + <parent>
23 + <groupId>org.onosproject</groupId>
24 + <artifactId>onos-snmp-providers</artifactId>
25 + <version>1.4.0-SNAPSHOT</version>
26 + <relativePath>../pom.xml</relativePath>
27 + </parent>
28 +
29 + <artifactId>onos-snmp-provider-device</artifactId>
30 + <packaging>bundle</packaging>
31 +
32 + <description>ONOS SNMP protocol device provider</description>
33 +
34 + <dependencies>
35 + <dependency>
36 + <groupId>org.osgi</groupId>
37 + <artifactId>org.osgi.compendium</artifactId>
38 + </dependency>
39 + <!-- <dependency>
40 + <groupId>javax.ws.rs</groupId>
41 + <artifactId>jsr311-api</artifactId>
42 + <version>1.1.1</version>
43 + </dependency>
44 + <dependency>
45 + <groupId>org.onosproject</groupId>
46 + <artifactId>onos-incubator-api</artifactId>
47 + </dependency>
48 + <dependency>
49 + <groupId>org.onosproject</groupId>
50 + <artifactId>onos-core-serializers</artifactId>
51 + <version>${project.version}</version>
52 + </dependency>-->
53 + </dependencies>
54 + <build>
55 + <plugins>
56 + <plugin>
57 + <groupId>org.apache.felix</groupId>
58 + <artifactId>maven-scr-plugin</artifactId>
59 + </plugin>
60 + </plugins>
61 + </build>
62 +
63 +</project>
64 +
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Licensed under the Apache License, Version 2.0 (the "License");
3 + * you may not use this file except in compliance with the License.
4 + * You may obtain a copy of the License at
5 + *
6 + * http://www.apache.org/licenses/LICENSE-2.0
7 + *
8 + * Unless required by applicable law or agreed to in writing, software
9 + * distributed under the License is distributed on an "AS IS" BASIS,
10 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 + * See the License for the specific language governing permissions and
12 + * limitations under the License.
13 + */
14 +package org.onosproject.provider.snmp.device.impl;
15 +
16 +import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.I_Device;
17 +import com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0._OidRegistry;
18 +import com.btisystems.pronx.ems.core.model.ClassRegistry;
19 +import com.btisystems.pronx.ems.core.model.IClassRegistry;
20 +import com.btisystems.pronx.ems.core.model.NetworkDevice;
21 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
22 +import java.io.IOException;
23 +import java.util.Arrays;
24 +import org.onosproject.net.device.DefaultDeviceDescription;
25 +import org.onosproject.net.device.DeviceDescription;
26 +import org.slf4j.Logger;
27 +import static org.slf4j.LoggerFactory.getLogger;
28 +import org.snmp4j.smi.OID;
29 +
30 +/**
31 + * A vendor-specific implementation supporting BTI Systems BTI-7000 equipment.
32 + */
33 +public class Bti7000DeviceDescriptionProvider implements SnmpDeviceDescriptionProvider {
34 + private final Logger log = getLogger(getClass());
35 + protected static final IClassRegistry CLASS_REGISTRY =
36 + new ClassRegistry(_OidRegistry.oidRegistry, I_Device.class);
37 + private static final String UNKNOWN = "unknown";
38 +
39 + @Override
40 + public DeviceDescription populateDescription(ISnmpSession session, DeviceDescription description) {
41 + NetworkDevice networkDevice = new NetworkDevice(CLASS_REGISTRY,
42 + session.getAddress().getHostAddress());
43 + try {
44 + session.walkDevice(networkDevice, Arrays.asList(new OID[]{
45 + CLASS_REGISTRY.getClassToOidMap().get(
46 + com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.mib_2.System.class)}));
47 +
48 + com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.mib_2.System systemTree =
49 + (com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.mib_2.System)
50 + networkDevice.getRootObject().getEntity(CLASS_REGISTRY.getClassToOidMap().get(
51 + com.btisystems.mibbler.mibs.bti7000.bti7000_13_2_0.mib_2.System.class));
52 + if (systemTree != null) {
53 + String[] systemComponents = systemTree.getSysDescr().split(";");
54 + return new DefaultDeviceDescription(description.deviceUri(), description.type(),
55 + systemComponents[0], systemComponents[2], systemComponents[3],
56 + UNKNOWN, description.chassisId());
57 + }
58 + } catch (IOException ex) {
59 + log.error("Error reading details for device {}.", session.getAddress(), ex);
60 + }
61 + return description;
62 + }
63 +
64 +}
1 +/*
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 +
17 +package org.onosproject.provider.snmp.device.impl;
18 + /**
19 + * The Device State is used to determine whether the device is active or inactive. This state information will help
20 + * Device Creator to add or delete the device from the core.
21 + */
22 + public enum DeviceState {
23 + /* Used to specify Active state of the device */
24 +
25 + ACTIVE,
26 + /* Used to specify inactive state of the device */
27 + INACTIVE,
28 + /* Used to specify invalid state of the device */
29 + INVALID
30 + }
1 +/*
2 + * Licensed under the Apache License, Version 2.0 (the "License");
3 + * you may not use this file except in compliance with the License.
4 + * You may obtain a copy of the License at
5 + *
6 + * http://www.apache.org/licenses/LICENSE-2.0
7 + *
8 + * Unless required by applicable law or agreed to in writing, software
9 + * distributed under the License is distributed on an "AS IS" BASIS,
10 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 + * See the License for the specific language governing permissions and
12 + * limitations under the License.
13 + */
14 +package org.onosproject.provider.snmp.device.impl;
15 +
16 +import com.btisystems.mibbler.mibs.netsnmp.netsnmp.I_Device;
17 +import com.btisystems.mibbler.mibs.netsnmp.netsnmp._OidRegistry;
18 +import com.btisystems.pronx.ems.core.model.ClassRegistry;
19 +import com.btisystems.pronx.ems.core.model.IClassRegistry;
20 +import com.btisystems.pronx.ems.core.model.NetworkDevice;
21 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
22 +import java.io.IOException;
23 +import java.util.Arrays;
24 +import org.apache.commons.lang.StringUtils;
25 +import org.onosproject.net.device.DefaultDeviceDescription;
26 +import org.onosproject.net.device.DeviceDescription;
27 +import org.slf4j.Logger;
28 +import static org.slf4j.LoggerFactory.getLogger;
29 +import org.snmp4j.smi.OID;
30 +
31 +/**
32 + * A agent-specific implementation supporting NET-SNMP agents.
33 + */
34 +public class NetSnmpDeviceDescriptionProvider implements SnmpDeviceDescriptionProvider {
35 + private final Logger log = getLogger(getClass());
36 + protected static final IClassRegistry CLASS_REGISTRY =
37 + new ClassRegistry(_OidRegistry.oidRegistry, I_Device.class);
38 + private static final String UNKNOWN = "unknown";
39 +
40 + @Override
41 + public DeviceDescription populateDescription(ISnmpSession session, DeviceDescription description) {
42 + NetworkDevice networkDevice = new NetworkDevice(CLASS_REGISTRY,
43 + session.getAddress().getHostAddress());
44 + try {
45 + session.walkDevice(networkDevice, Arrays.asList(new OID[]{
46 + CLASS_REGISTRY.getClassToOidMap().get(
47 + com.btisystems.mibbler.mibs.netsnmp.netsnmp.mib_2.System.class)}));
48 +
49 + com.btisystems.mibbler.mibs.netsnmp.netsnmp.mib_2.System systemTree =
50 + (com.btisystems.mibbler.mibs.netsnmp.netsnmp.mib_2.System)
51 + networkDevice.getRootObject().getEntity(CLASS_REGISTRY.getClassToOidMap().get(
52 + com.btisystems.mibbler.mibs.netsnmp.netsnmp.mib_2.System.class));
53 + if (systemTree != null) {
54 + // TODO SNMP sys-contacts may be verbose; ONOS-GUI doesn't abbreviate fields neatly;
55 + // so cut it here until supported in prop displayer
56 + String manufacturer = StringUtils.abbreviate(systemTree.getSysContact(), 20);
57 + return new DefaultDeviceDescription(description.deviceUri(), description.type(), manufacturer,
58 + UNKNOWN, UNKNOWN, UNKNOWN, description.chassisId());
59 + }
60 + } catch (IOException ex) {
61 + log.error("Error reading details for device {}.", session.getAddress(), ex);
62 + }
63 + return description;
64 + }
65 +
66 +}
1 +/*
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 +package org.onosproject.provider.snmp.device.impl;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +import static org.slf4j.LoggerFactory.getLogger;
20 +
21 +
22 +import org.slf4j.Logger;
23 +
24 +/**
25 + * This is a logical representation of actual SNMP device, carrying all the necessary information to connect and execute
26 + * SNMP operations.
27 + */
28 +public class SnmpDevice {
29 +
30 + private final Logger log = getLogger(SnmpDevice.class);
31 +
32 +
33 + private static final int DEFAULT_SNMP_PORT = 161;
34 +
35 + private final String snmpHost;
36 + private int snmpPort = DEFAULT_SNMP_PORT;
37 + private final String community;
38 + private boolean reachable = false;
39 +
40 + private DeviceState deviceState = DeviceState.INVALID;
41 +
42 + protected SnmpDevice(String snmpHost, int snmpPort, String community) {
43 +
44 + this.snmpHost = checkNotNull(snmpHost, "SNMP Device IP cannot be null");
45 + this.snmpPort = checkNotNull(snmpPort, "SNMP Device snmp port cannot be null");
46 + this.community = community;
47 + }
48 +
49 + /**
50 + * This will try to connect to SNMP device.
51 + *
52 + */
53 + public void init() {
54 +
55 + reachable = true;
56 + }
57 +
58 + /**
59 + * This would return host IP and host Port, used by this particular SNMP Device.
60 + *
61 + * @return Device Information.
62 + */
63 + public String deviceInfo() {
64 + return new StringBuilder("host: ").append(snmpHost).append(". port: ")
65 + .append(snmpPort).toString();
66 + }
67 +
68 + /**
69 + * This will terminate the device connection.
70 + */
71 + public void disconnect() {
72 + log.info("disconnect");
73 + reachable = false;
74 + }
75 +
76 + /**
77 + * This api is intended to know whether the device is connected or not.
78 + *
79 + * @return true if connected
80 + */
81 + public boolean isReachable() {
82 + return reachable;
83 + }
84 +
85 + /**
86 + * This will return the IP used connect ssh on the device.
87 + *
88 + * @return SNMP Device IP
89 + */
90 + public String getSnmpHost() {
91 + return snmpHost;
92 + }
93 +
94 + /**
95 + * This will return the SSH Port used connect the device.
96 + *
97 + * @return SSH Port number
98 + */
99 + public int getSnmpPort() {
100 + return snmpPort;
101 + }
102 +
103 + public String getCommunity() {
104 + return community;
105 + }
106 +
107 + /**
108 + * Retrieve current state of the device.
109 + *
110 + * @return Current Device State
111 + */
112 + public DeviceState getDeviceState() {
113 + return deviceState;
114 + }
115 +
116 + /**
117 + * This is set the state information for the device.
118 + *
119 + * @param deviceState Next Device State
120 + */
121 + public void setDeviceState(DeviceState deviceState) {
122 + this.deviceState = deviceState;
123 + }
124 +
125 + /**
126 + * Check whether the device is in Active state.
127 + *
128 + * @return true if the device is Active
129 + */
130 + public boolean isActive() {
131 + return deviceState == DeviceState.ACTIVE;
132 + }
133 +
134 +}
1 +/*
2 + * Licensed under the Apache License, Version 2.0 (the "License");
3 + * you may not use this file except in compliance with the License.
4 + * You may obtain a copy of the License at
5 + *
6 + * http://www.apache.org/licenses/LICENSE-2.0
7 + *
8 + * Unless required by applicable law or agreed to in writing, software
9 + * distributed under the License is distributed on an "AS IS" BASIS,
10 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 + * See the License for the specific language governing permissions and
12 + * limitations under the License.
13 + */
14 +package org.onosproject.provider.snmp.device.impl;
15 +
16 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
17 +import org.onosproject.net.device.DeviceDescription;
18 +
19 +/**
20 + * Abstraction of an entity which updates a device description with information retrieved via SNMP.
21 + */
22 +public interface SnmpDeviceDescriptionProvider {
23 +
24 + /**
25 + * Generated an updated device description.
26 + *
27 + * @param session SNMP session
28 + * @param description old device description
29 + * @return new updated description
30 + */
31 + DeviceDescription populateDescription(ISnmpSession session, DeviceDescription description);
32 +
33 +}
1 +/*
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 +package org.onosproject.provider.snmp.device.impl;
17 +
18 +import com.btisystems.pronx.ems.core.snmp.DefaultSnmpConfigurationFactory;
19 +import com.btisystems.pronx.ems.core.snmp.ISnmpConfiguration;
20 +import com.btisystems.pronx.ems.core.snmp.ISnmpConfigurationFactory;
21 +import com.btisystems.pronx.ems.core.snmp.ISnmpSession;
22 +import com.btisystems.pronx.ems.core.snmp.ISnmpSessionFactory;
23 +import com.btisystems.pronx.ems.core.snmp.SnmpSessionFactory;
24 +import com.btisystems.pronx.ems.core.snmp.V2cSnmpConfiguration;
25 +import static com.google.common.base.Strings.isNullOrEmpty;
26 +import java.io.IOException;
27 +import static org.onlab.util.Tools.delay;
28 +import static org.onlab.util.Tools.get;
29 +import static org.onlab.util.Tools.groupedThreads;
30 +import static org.slf4j.LoggerFactory.getLogger;
31 +
32 +import java.net.URI;
33 +import java.net.URISyntaxException;
34 +import java.util.Dictionary;
35 +import java.util.HashMap;
36 +import java.util.Map;
37 +import java.util.concurrent.ConcurrentHashMap;
38 +import java.util.concurrent.ExecutorService;
39 +import java.util.concurrent.Executors;
40 +import java.util.concurrent.TimeUnit;
41 +
42 +import org.apache.felix.scr.annotations.Activate;
43 +import org.apache.felix.scr.annotations.Component;
44 +import org.apache.felix.scr.annotations.Deactivate;
45 +import org.apache.felix.scr.annotations.Modified;
46 +import org.apache.felix.scr.annotations.Property;
47 +import org.apache.felix.scr.annotations.Reference;
48 +import org.apache.felix.scr.annotations.ReferenceCardinality;
49 +import org.onlab.packet.ChassisId;
50 +import org.onosproject.cfg.ComponentConfigService;
51 +import org.onosproject.cluster.ClusterService;
52 +import org.onosproject.net.Device;
53 +import org.onosproject.net.DeviceId;
54 +import org.onosproject.net.MastershipRole;
55 +import org.onosproject.net.device.DefaultDeviceDescription;
56 +import org.onosproject.net.device.DeviceDescription;
57 +import org.onosproject.net.device.DeviceProvider;
58 +import org.onosproject.net.device.DeviceProviderRegistry;
59 +import org.onosproject.net.device.DeviceProviderService;
60 +import org.onosproject.net.device.DeviceService;
61 +import org.onosproject.net.provider.AbstractProvider;
62 +import org.onosproject.net.provider.ProviderId;
63 +import org.osgi.service.component.ComponentContext;
64 +import org.slf4j.Logger;
65 +
66 +/**
67 + * Provider which will try to fetch the details of SNMP devices from the core and run a capability discovery on each of
68 + * the device.
69 + */
70 +@Component(immediate = true)
71 +public class SnmpDeviceProvider extends AbstractProvider
72 + implements DeviceProvider {
73 +
74 + private final Logger log = getLogger(SnmpDeviceProvider.class);
75 +
76 + private static final String UNKNOWN = "unknown";
77 +
78 + protected Map<DeviceId, SnmpDevice> snmpDeviceMap = new ConcurrentHashMap<>();
79 +
80 + private DeviceProviderService providerService;
81 +
82 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 + protected DeviceProviderRegistry providerRegistry;
84 +
85 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 + protected DeviceService deviceService;
87 +
88 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 + protected ClusterService clusterService;
90 +
91 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 + protected ComponentConfigService cfgService;
93 +
94 + private final ExecutorService deviceBuilder = Executors
95 + .newFixedThreadPool(1, groupedThreads("onos/snmp", "device-creator"));
96 +
97 + // Delay between events in ms.
98 + private static final int EVENTINTERVAL = 5;
99 +
100 + private static final String SCHEME = "snmp";
101 +
102 + @Property(name = "devConfigs", value = "", label = "Instance-specific configurations")
103 + private String devConfigs = null;
104 +
105 + @Property(name = "devPasswords", value = "", label = "Instance-specific password")
106 + private String devPasswords = null;
107 +
108 + //TODO Could be replaced with a service lookup, and bundles per device variant.
109 + Map<String, SnmpDeviceDescriptionProvider> providers = new HashMap<>();
110 +
111 + private final ISnmpSessionFactory sessionFactory;
112 +
113 + /**
114 + * Creates a provider with the supplier identifier.
115 + */
116 + public SnmpDeviceProvider() {
117 + super(new ProviderId("snmp", "org.onosproject.provider.device"));
118 + sessionFactory = new SnmpSessionFactory(
119 + new DefaultSnmpConfigurationFactory(new V2cSnmpConfiguration()));
120 + providers.put("1.3.6.1.4.1.18070.2.2", new Bti7000DeviceDescriptionProvider());
121 + providers.put("1.3.6.1.4.1.20408", new NetSnmpDeviceDescriptionProvider());
122 + }
123 +
124 + @Activate
125 + public void activate(ComponentContext context) {
126 + log.info("activating for snmp devices ...");
127 + cfgService.registerProperties(getClass());
128 + providerService = providerRegistry.register(this);
129 + modified(context);
130 + log.info("activated ok");
131 + }
132 +
133 + @Deactivate
134 + public void deactivate(ComponentContext context) {
135 +
136 + log.info("deactivating for snmp devices ...");
137 +
138 + cfgService.unregisterProperties(getClass(), false);
139 + try {
140 + snmpDeviceMap
141 + .entrySet().stream().forEach((deviceEntry) -> {
142 + deviceBuilder.submit(new DeviceCreator(deviceEntry.getValue(), false));
143 + });
144 + deviceBuilder.awaitTermination(1000, TimeUnit.MILLISECONDS);
145 + } catch (InterruptedException e) {
146 + log.error("Device builder did not terminate");
147 + }
148 + deviceBuilder.shutdownNow();
149 + snmpDeviceMap.clear();
150 + providerRegistry.unregister(this);
151 + providerService = null;
152 + log.info("Stopped");
153 + }
154 +
155 + @Modified
156 + public void modified(ComponentContext context) {
157 + log.info("modified ...");
158 +
159 + if (context == null) {
160 + log.info("No configuration file");
161 + return;
162 + }
163 + Dictionary<?, ?> properties = context.getProperties();
164 +
165 + log.info("properties={}", context.getProperties());
166 +
167 + String deviceCfgValue = get(properties, "devConfigs");
168 + log.info("Settings: devConfigs={}", deviceCfgValue);
169 + if (!isNullOrEmpty(deviceCfgValue)) {
170 + addOrRemoveDevicesConfig(deviceCfgValue);
171 + }
172 + log.info("... modified");
173 +
174 + }
175 +
176 + private void addOrRemoveDevicesConfig(String deviceConfig) {
177 + for (String deviceEntry : deviceConfig.split(",")) {
178 + SnmpDevice device = processDeviceEntry(deviceEntry);
179 + if (device != null) {
180 + log.info("Device Detail:host={}, port={}, state={}",
181 + new Object[]{device.getSnmpHost(),
182 + device.getSnmpPort(),
183 + device.getDeviceState().name()}
184 + );
185 + if (device.isActive()) {
186 + deviceBuilder.submit(new DeviceCreator(device, true));
187 + } else {
188 + deviceBuilder.submit(new DeviceCreator(device, false));
189 + }
190 + }
191 + }
192 + }
193 +
194 + private SnmpDevice processDeviceEntry(String deviceEntry) {
195 + if (deviceEntry == null) {
196 + log.info("No content for Device Entry, so cannot proceed further.");
197 + return null;
198 + }
199 + log.info("Trying to convert {} to a SNMP Device Object", deviceEntry);
200 + SnmpDevice device = null;
201 + try {
202 + String userInfo = deviceEntry.substring(0, deviceEntry
203 + .lastIndexOf('@'));
204 + String hostInfo = deviceEntry.substring(deviceEntry
205 + .lastIndexOf('@') + 1);
206 + String[] infoSplit = userInfo.split(":");
207 + String username = infoSplit[0];
208 + String password = infoSplit[1];
209 + infoSplit = hostInfo.split(":");
210 + String hostIp = infoSplit[0];
211 + Integer hostPort;
212 + try {
213 + hostPort = Integer.parseInt(infoSplit[1]);
214 + } catch (NumberFormatException nfe) {
215 + log.error("Bad Configuration Data: Failed to parse host port number string: "
216 + + infoSplit[1]);
217 + throw nfe;
218 + }
219 + String deviceState = infoSplit[2];
220 + if (isNullOrEmpty(username) || isNullOrEmpty(password)
221 + || isNullOrEmpty(hostIp) || hostPort == 0) {
222 + log.warn("Bad Configuration Data: both user and device information parts of Configuration "
223 + + deviceEntry + " should be non-nullable");
224 + } else {
225 + device = new SnmpDevice(hostIp, hostPort, password);
226 + if (!isNullOrEmpty(deviceState)) {
227 + if (deviceState.toUpperCase().equals(DeviceState.ACTIVE.name())) {
228 + device.setDeviceState(DeviceState.ACTIVE);
229 + } else if (deviceState.toUpperCase()
230 + .equals(DeviceState.INACTIVE.name())) {
231 + device.setDeviceState(DeviceState.INACTIVE);
232 + } else {
233 + log.warn("Device State Information can not be empty, so marking the state as INVALID");
234 + device.setDeviceState(DeviceState.INVALID);
235 + }
236 + } else {
237 + log.warn("The device entry do not specify state information, so marking the state as INVALID");
238 + device.setDeviceState(DeviceState.INVALID);
239 + }
240 + }
241 + } catch (ArrayIndexOutOfBoundsException aie) {
242 + log.error("Error while reading config infromation from the config file: "
243 + + "The user, host and device state infomation should be "
244 + + "in the order 'userInfo@hostInfo:deviceState'"
245 + + deviceEntry, aie);
246 + } catch (Exception e) {
247 + log.error("Error while parsing config information for the device entry: "
248 + + deviceEntry, e);
249 + }
250 + return device;
251 + }
252 +
253 + @Override
254 + public void triggerProbe(DeviceId deviceId) {
255 + // TODO SNMP devices should be polled at scheduled intervals to retrieve their
256 + // reachability status and other details e.g.swVersion, serialNumber,chassis,
257 + }
258 +
259 + @Override
260 + public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
261 +
262 + }
263 +
264 + @Override
265 + public boolean isReachable(DeviceId deviceId) {
266 + SnmpDevice snmpDevice = snmpDeviceMap.get(deviceId);
267 + if (snmpDevice == null) {
268 + log.warn("BAD REQUEST: the requested device id: "
269 + + deviceId.toString()
270 + + " is not associated to any SNMP Device");
271 + return false;
272 + }
273 + return snmpDevice.isReachable();
274 + }
275 +
276 + /**
277 + * This class is intended to add or remove Configured SNMP Devices. Functionality relies on 'createFlag' and
278 + * 'SnmpDevice' content. The functionality runs as a thread and depending on the 'createFlag' value it will create
279 + * or remove Device entry from the core.
280 + */
281 + private class DeviceCreator implements Runnable {
282 +
283 + private SnmpDevice device;
284 + private boolean createFlag;
285 +
286 + public DeviceCreator(SnmpDevice device, boolean createFlag) {
287 + this.device = device;
288 + this.createFlag = createFlag;
289 + }
290 +
291 + @Override
292 + public void run() {
293 + if (createFlag) {
294 + log.info("Trying to create Device Info on ONOS core");
295 + advertiseDevices();
296 + } else {
297 + log.info("Trying to remove Device Info on ONOS core");
298 + removeDevices();
299 + }
300 + }
301 +
302 + /**
303 + * For each SNMP Device, remove the entry from the device store.
304 + */
305 + private void removeDevices() {
306 + if (device == null) {
307 + log.warn("The Request SNMP Device is null, cannot proceed further");
308 + return;
309 + }
310 + try {
311 + DeviceId did = getDeviceId();
312 + if (!snmpDeviceMap.containsKey(did)) {
313 + log.error("BAD Request: 'Currently device is not discovered, "
314 + + "so cannot remove/disconnect the device: "
315 + + device.deviceInfo() + "'");
316 + return;
317 + }
318 + providerService.deviceDisconnected(did);
319 + device.disconnect();
320 + snmpDeviceMap.remove(did);
321 + delay(EVENTINTERVAL);
322 + } catch (URISyntaxException uriSyntaxExcpetion) {
323 + log.error("Syntax Error while creating URI for the device: "
324 + + device.deviceInfo()
325 + + " couldn't remove the device from the store",
326 + uriSyntaxExcpetion);
327 + }
328 + }
329 +
330 + /**
331 + * Initialize SNMP Device object, and notify core saying device connected.
332 + */
333 + private void advertiseDevices() {
334 + try {
335 + if (device == null) {
336 + log.warn("The Request SNMP Device is null, cannot proceed further");
337 + return;
338 + }
339 + device.init();
340 + DeviceId did = getDeviceId();
341 + ChassisId cid = new ChassisId();
342 +
343 +
344 + DeviceDescription desc = new DefaultDeviceDescription(
345 + did.uri(), Device.Type.OTHER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid);
346 +
347 + desc = populateDescriptionFromDevice(did, desc);
348 +
349 + log.info("Persisting Device " + did.uri().toString());
350 +
351 + snmpDeviceMap.put(did, device);
352 + providerService.deviceConnected(did, desc);
353 + log.info("Done with Device Info Creation on ONOS core. Device Info: "
354 + + device.deviceInfo() + " " + did.uri().toString());
355 + delay(EVENTINTERVAL);
356 + } catch (URISyntaxException e) {
357 + log.error("Syntax Error while creating URI for the device: "
358 + + device.deviceInfo()
359 + + " couldn't persist the device onto the store", e);
360 + } catch (Exception e) {
361 + log.error("Error while initializing session for the device: "
362 + + (device != null ? device.deviceInfo() : null), e);
363 + }
364 + }
365 +
366 + private DeviceDescription populateDescriptionFromDevice(DeviceId did, DeviceDescription desc) {
367 + String[] deviceComponents = did.toString().split(":");
368 + if (deviceComponents.length > 1) {
369 + String ipAddress = deviceComponents[1];
370 + String port = deviceComponents[2];
371 +
372 + ISnmpConfiguration config = new V2cSnmpConfiguration();
373 + config.setPort(Integer.parseInt(port));
374 +
375 + try (ISnmpSession session = sessionFactory.createSession(config, ipAddress)) {
376 + // Each session will be auto-closed.
377 + String deviceOID = session.identifyDevice();
378 +
379 + if (providers.containsKey(deviceOID)) {
380 + desc = providers.get(deviceOID).populateDescription(session, desc);
381 + }
382 +
383 + } catch (IOException | RuntimeException ex) {
384 + log.error("Failed to walk device.", ex.getMessage());
385 + log.debug("Detailed problem was ", ex);
386 + }
387 + }
388 + return desc;
389 + }
390 +
391 + /**
392 + * This will build a device id for the device.
393 + */
394 + private DeviceId getDeviceId() throws URISyntaxException {
395 + String additionalSSP = new StringBuilder(
396 + device.getSnmpHost()).append(":")
397 + .append(device.getSnmpPort()).toString();
398 + return DeviceId.deviceId(new URI(SCHEME, additionalSSP,
399 + null));
400 + }
401 + }
402 +
403 + protected ISnmpSessionFactory getSessionFactory(ISnmpConfigurationFactory configurationFactory) {
404 + return new SnmpSessionFactory(configurationFactory);
405 + }
406 +}
1 +/*
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 +
17 +/**
18 + * Provider that uses SNMP capability request as a means of infrastructure device discovery.
19 + */
20 +package org.onosproject.provider.snmp.device.impl;
...\ No newline at end of file ...\ No newline at end of file
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- 2 <!--
3 - ~ Copyright 2014 Open Networking Laboratory 3 + ~ Copyright 2015 Open Networking Laboratory
4 ~ 4 ~
5 ~ Licensed under the Apache License, Version 2.0 (the "License"); 5 ~ Licensed under the Apache License, Version 2.0 (the "License");
6 ~ you may not use this file except in compliance with the License. 6 ~ you may not use this file except in compliance with the License.
...@@ -29,10 +29,55 @@ ...@@ -29,10 +29,55 @@
29 <artifactId>onos-snmp-providers</artifactId> 29 <artifactId>onos-snmp-providers</artifactId>
30 <packaging>pom</packaging> 30 <packaging>pom</packaging>
31 31
32 - <description>ONOS SNMP Protocol Adapters</description> 32 + <description>ONOS SNMP protocol adapters</description>
33 33
34 <modules> 34 <modules>
35 + <module>device</module>
36 + <module>app</module>
35 <module>alarm</module> 37 <module>alarm</module>
36 </modules> 38 </modules>
37 39
40 + <dependencies>
41 + <dependency>
42 + <groupId>org.apache.servicemix.bundles</groupId>
43 + <artifactId>org.apache.servicemix.bundles.snmp4j</artifactId>
44 + <version>2.3.4_1</version>
45 + <exclusions>
46 + <exclusion>
47 + <artifactId>log4j</artifactId>
48 + <groupId>log4j</groupId>
49 + </exclusion>
50 + </exclusions>
51 + </dependency>
52 +
53 + <dependency>
54 + <groupId>com.btisystems</groupId>
55 + <artifactId>snmp-core</artifactId>
56 + <version>1.3-SNAPSHOT</version>
57 + </dependency>
58 +
59 + <dependency>
60 + <groupId>com.btisystems.mibbler.mibs</groupId>
61 + <artifactId>bti7000</artifactId>
62 + <version>1.0-SNAPSHOT</version>
63 + </dependency>
64 +
65 + <dependency>
66 + <groupId>com.btisystems.mibbler.mibs</groupId>
67 + <artifactId>net-snmp</artifactId>
68 + <version>1.0-SNAPSHOT</version>
69 + </dependency>
70 + </dependencies>
71 + <repositories>
72 + <repository>
73 + <!-- TODO move over to release snmp-core when it becomes available.-->
74 + <id>oss.sonatype.org-snapshot</id>
75 + <url>http://oss.sonatype.org/content/repositories/snapshots</url>
76 + <snapshots>
77 + <enabled>true</enabled>
78 + </snapshots>
79 + </repository>
80 + </repositories>
81 +
82 +
38 </project> 83 </project>
......
1 -#
2 -# devices which may have faults.
3 -# TODO change to NetworkConfig subsystem.
4 -#
5 -fmDevices = 172.27.7.110,172.27.7.110,3.3.3.3
6 -
1 +#
2 +# devices which support SNMP, these may support SNMP fault-management.
3 +# demo.snmplabs.com is a publically available SNMP agent-simulator accessible via the internet, see http://snmpsim.sourceforge.net/public-snmp-simulator.html
4 +#
5 +devConfigs = bti7000:public@172.27.7.109:161:active,net-snmp:public@demo.snmplabs.com:161:active,net-snmp:public@demo.snmplabs.com:1161:active,net-snmp:public@demo.snmplabs.com:2161:active,net-snmp:public@demo.snmplabs.com:3161:active