Compare commits

...

37 Commits

Author SHA1 Message Date
Thomas-Leung2021
90ac57b988 [WIFI-3041] move if statement to make it more logical 2021-07-19 17:52:49 -04:00
Thomas-Leung2021
0cc90764c6 [WIFI-3041] move if statusment for custmerId check to a different location 2021-07-19 17:00:54 -04:00
Thomas-Leung2021
3d2f4db32a [WIFI-3041] remove unnecessary dependencies 2021-07-16 12:22:23 -04:00
Thomas-Leung2021
c75d44ff03 [WIFI-3041] create a new EquipmentCustomerChangedEvent to handle status and alarm migration 2021-07-16 10:44:23 -04:00
Thomas-Leung2021
799b243cc4 [WIFI-3041] move alarms to new customerId if customerId changed 2021-07-15 16:45:07 -04:00
Mike Hansen
8834c33d90 Merge pull request #129 from Telecominfraproject/WIFI-3042-alarms-by-alarmcode
[WIFI-3042] Add Alarm endpoint for get alarms by AlarmCode
2021-07-15 09:26:20 -04:00
Norm Traxler
e9c54a892b [WIFI-3042] Add Alarm endpoint for get alarms by AlarmCode 2021-07-14 20:18:22 -04:00
Mike Hansen
8353dd375f Control LED off via Equipment AP profile
Signed-off-by: Mike Hansen <mike.hansen@connectus.ai>
2021-07-14 18:45:33 -04:00
Mike Hansen
46de84b28b Add NULL check in EquipmentController
Signed-off-by: Mike Hansen <mike.hansen@connectus.ai>
2021-07-14 18:00:10 -04:00
Mike Hansen
9edca1fd9d CloudBackend:
Control LED off via Equipment AP profile

Signed-off-by: Mike Hansen <mike.hansen@connectus.ai>
2021-07-14 17:30:06 -04:00
Mike Hansen
5714c9bf32 CloudBackend:
Control LED off via Equipment AP profile and Show LED status in EQUIPMENT_ADMIN status

Signed-off-by: Mike Hansen <mike.hansen@connectus.ai>
2021-07-14 16:03:39 -04:00
Mike Hansen
2b2e34a064 Merge pull request #128 from Telecominfraproject/WIFI-2987
[WIFI-2987] add protocol status when switching customer
2021-07-13 14:09:02 -04:00
Thomas-Leung2021
d7a75faf4c check when status is null 2021-07-13 12:10:04 -04:00
Thomas-Leung2021
5fd977f064 [WIFI-2987] add protocol status when switching customer 2021-07-12 14:47:36 -04:00
Mike Hansen
bafec1fdd8 Merge pull request #127 from Telecominfraproject/hotfix/wifi-2970
[WIFI-2970] add equipment admin status when switching customer
2021-07-09 10:52:49 -04:00
Thomas-Leung2021
6b046e0a7a [WIFI-2970] remove unnecessary comments 2021-07-09 10:48:40 -04:00
Thomas-Leung2021
fb6604cdf5 add required dependencies in tests for new changes in EquipmentController 2021-07-08 17:48:20 -04:00
Thomas-Leung2021
2c1c60344e add equipment admin status when switching customer 2021-07-08 17:47:26 -04:00
Mike Hansen
9e959e258f Merge pull request #126 from Telecominfraproject/WIFI-2932-Client-ip-event
[WIFI-2932] Change IP event ipAddress from byte[] to InetAddress
2021-07-06 10:21:04 -04:00
Norm Traxler
2410233046 [WIFI-2932] Change IP event ipAddress from byte[] to InetAddress 2021-07-05 17:58:01 -04:00
norm-traxler
a7f91a29f8 Merge pull request #125 from Telecominfraproject/updateAPI
Update APIs to reflect new map in EquipmentChannelStatusData
2021-06-28 16:23:39 -04:00
Thomas-Leung2021
80cd0abd58 Update APIs to reflect new map in EquipmentChannelStatusData 2021-06-28 11:50:49 -04:00
Mike Hansen
4555ff339b Merge pull request #124 from Telecominfraproject/feature/netexp-2237
add tx_power status
2021-06-25 13:07:27 -04:00
Thomas-Leung2021
04a13877d1 add tx_power status 2021-06-25 12:39:30 -04:00
Mike Hansen
e148bab291 Merge pull request #123 from Telecominfraproject/WIFI-2699-modify-GET-/portal/profile/equipmentCounts-to-support-child-profiles-for-the-count
WIFI-2699  Modify GET /portal/profile/equipmentCounts to support child profiles for the count
2021-06-24 10:09:38 -04:00
Thomas Currie
9ad3cec4af rework top level profile tracking, so as to not include any profiles that were not in the Set argument 2021-06-23 11:30:06 -04:00
Thomas Currie
dc0b838f83 complete the test case cleanup 2021-06-23 11:11:54 -04:00
Thomas Currie
7cac7fff3f rework the algorithm at endpoint /portal/profile/equipmentCounts to include the correct child profile count for equipment 2021-06-23 10:58:02 -04:00
Mike Hansen
b48340b709 Merge pull request #122 from Telecominfraproject/disable_eq_alarms_sp
disable equipment-alarms-sp functionality, part of task to move the r…
2021-06-22 16:03:36 -04:00
Mike Hansen
44b3836758 disable equipment-alarms-sp functionality, part of task to move the raising and clearing of the threshold alarms into the gateway controller when the device information is received
Signed-off-by: Mike Hansen <mike.hansen@connectus.ai>
2021-06-22 15:43:09 -04:00
Mike Hansen
4f0b032549 Merge branch 'disable_eq_alarms_sp' of github.com:Telecominfraproject/wlan-cloud-services into disable_eq_alarms_sp 2021-06-22 15:40:54 -04:00
Mike Hansen
5ba0c4c242 Merge pull request #121 from Telecominfraproject/WIFI-2698-Update-visibility-of-fields-in-PortalUserDAO
WIFI-2698-Update-visibility-of-fields-in-PortalUserDAO
2021-06-22 10:42:01 -04:00
Mike Hansen
304e80332a disable equipment-alarms-sp functionality, part of task to move the raising and clearing of the threshold alarms into the gateway controller when the device information is received
Signed-off-by: Mike Hansen <mike.hansen@connectus.ai>
2021-06-22 10:19:41 -04:00
Thomas Currie
9fd3e73398 increase visibility of some fields in PortalUserDAO to allow classes to extend upon without duplication of values 2021-06-21 19:59:45 -04:00
Mike Hansen
b9db744aee Merge pull request #120 from Telecominfraproject/updateAPI
[WIFI-2646] update API to support WPA3-EAP-192
2021-06-17 13:43:53 -04:00
norm-traxler
1eee65d284 Merge pull request #119 from Telecominfraproject/WIFI-2670_2
[WIFI-2670] Add more counters to the ClientSessionCounts
2021-06-17 13:11:18 -04:00
Thomas-Leung2021
d0a0ed59fe update API to support WPA3-EAP-192 2021-06-17 12:14:12 -04:00
47 changed files with 1212 additions and 1631 deletions

View File

@@ -121,6 +121,10 @@ public class AlarmDatastoreCassandra implements AlarmDatastore {
" from " + TABLE_NAME + " " +
" where customerId = ? ";
private static final String CQL_GET_ALL =
"select " + ALL_COLUMNS +
" from " + TABLE_NAME + " ";
private static final String CQL_GET_LASTMOD_BY_ID =
"select lastModifiedTimestamp " +
" from "+TABLE_NAME+" " +
@@ -922,4 +926,51 @@ public class AlarmDatastoreCassandra implements AlarmDatastore {
return alarmCounts;
}
@Override
public List<Alarm> get(Set<AlarmCode> alarmCodes, long createdAfterTimestamp) {
if (alarmCodes == null || alarmCodes.isEmpty()) {
throw new IllegalArgumentException("alarmCodes must be provided");
}
LOG.debug("Looking up Alarms for alarmCodes {} createdAfter {}", alarmCodes, createdAfterTimestamp);
String query = CQL_GET_ALL;
// add filters for the query
ArrayList<Object> queryArgs = new ArrayList<>();
// add alarmCodes filters
alarmCodes.forEach(ac -> queryArgs.add(ac.getId()));
StringBuilder strb = new StringBuilder(100);
strb.append("where alarmCode in (");
for (int i = 0; i < alarmCodes.size(); i++) {
strb.append("?");
if (i < alarmCodes.size() - 1) {
strb.append(",");
}
}
strb.append(") ");
if (createdAfterTimestamp > 0) {
strb.append(" and createdTimestamp > ?");
queryArgs.add(createdAfterTimestamp);
}
strb.append(" allow filtering");
query += strb.toString();
List<Alarm> ret = new ArrayList<>();
PreparedStatement preparedStmt_getListForCustomer = cqlSession.prepare(query);
ResultSet rs = cqlSession.execute(preparedStmt_getListForCustomer.bind(queryArgs.toArray()));
rs.forEach(row -> ret.add(alarmRowMapper.mapRow(row)));
LOG.debug("Found {} Alarms for alarmCodes {} createdAfter {}", ret.size(), alarmCodes, createdAfterTimestamp);
return ret;
}
}

View File

@@ -356,4 +356,25 @@ public class AlarmDatastoreInMemory extends BaseInMemoryDatastore implements Ala
return alarmCounts;
}
@Override
public List<Alarm> get(Set<AlarmCode> alarmCodeSet, long createdAfterTimestamp) {
if (alarmCodeSet == null || alarmCodeSet.isEmpty()) {
throw new IllegalArgumentException("alarmCodeSet must be provided");
}
List<Alarm> ret = new ArrayList<>();
idToAlarmMap.values().forEach(a -> {
if (alarmCodeSet.contains(a.getAlarmCode()) && a.getCreatedTimestamp() > createdAfterTimestamp) {
ret.add(a.clone());
}
});
LOG.debug("Found Alarms {}", ret);
return ret;
}
}

View File

@@ -71,4 +71,14 @@ public interface AlarmDatastore {
*/
AlarmCounts getAlarmCounts(int customerId, Set<Long> equipmentIdSet, Set<AlarmCode> alarmCodeSet, Boolean acknowledged);
/**
* Retrieves a list of Alarms for the given alarm codes.
*
* @param alarmCodeSet - null or empty means include all alarm codes
* @param createdAfterTimestamp
* @return list of matching Alarm objects.
* @throws IllegalArgumentException if supplied alarmCodeSet is null or empty
*/
List<Alarm> get(Set<AlarmCode> alarmCodeSet, long createdAfterTimestamp);
}

View File

@@ -113,5 +113,16 @@ public interface AlarmServiceInterface {
* @return alarm counts for the given filters
*/
AlarmCounts getAlarmCounts(int customerId, Set<Long> equipmentIdSet, Set<AlarmCode> alarmCodeSet, Boolean acknowledged);
/**
* Retrieves a list of Alarms for the given alarm codes.
*
* @param alarmCodeSet - null or empty means include all alarm codes
* @param createdAfterTimestamp
* @return list of matching Alarm objects.
* @throws IllegalArgumentException if supplied alarmCodeSet is null or empty
*/
List<Alarm> get(Set<AlarmCode> alarmCodeSet, long createdAfterTimestamp);
}

View File

@@ -47,6 +47,10 @@ public class AlarmServiceLocal implements AlarmServiceInterface {
return alarmController.getAllForEquipment(customerId, equipmentIdSet, alarmCodeSet, createdAfterTimestamp);
}
@Override
public List<Alarm> get(Set<AlarmCode> alarmCodeSet, long createdAfterTimestamp) {
return alarmController.getAllForAlarmCode(alarmCodeSet, createdAfterTimestamp);
}
@Override
public Alarm update(Alarm alarm) {

View File

@@ -64,6 +64,5 @@
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -241,14 +241,45 @@ public class AlarmServiceRemote extends BaseRemoteClient implements AlarmService
return ret;
}
@Override
public List<Alarm> get(Set<AlarmCode> alarmCodeSet, long createdAfterTimestamp) {
LOG.debug("get({},{})", alarmCodeSet, createdAfterTimestamp);
if (alarmCodeSet == null || alarmCodeSet.isEmpty()) {
throw new IllegalArgumentException("alarmCodeSet must be provided");
}
String alarmCodeSetStr = alarmCodeSet.toString();
// remove [] around the string, otherwise will get:
// Failed to convert value of type 'java.lang.String' to required
// type 'java.util.Set'; nested exception is
// java.lang.NumberFormatException: For input string: "[690]"
alarmCodeSetStr = alarmCodeSetStr.substring(1, alarmCodeSetStr.length() - 1);
try {
ResponseEntity<List<Alarm>> responseEntity =
restTemplate.exchange(getBaseUrl() + "/forAlarmCode?alarmCodeSet={alarmCodeSetStr}&createdAfterTimestamp={createdAfterTimestamp}",
HttpMethod.GET, null, Alarm_LIST_CLASS_TOKEN, alarmCodeSetStr, createdAfterTimestamp);
List<Alarm> result = responseEntity.getBody();
if (null == result) {
result = Collections.emptyList();
}
LOG.debug("get({},{}) return {} entries", alarmCodeSet, createdAfterTimestamp, result.size());
return result;
} catch (Exception exp) {
LOG.error("getAllInSet({},{}) exception ", alarmCodeSet, createdAfterTimestamp, exp);
throw exp;
}
}
public String getBaseUrl() {
if(baseUrl==null) {
baseUrl = environment.getProperty("tip.wlan.alarmServiceBaseUrl").trim()+"/api/alarm";
}
return baseUrl;
return baseUrl;
}
}

View File

@@ -1,70 +1,70 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<artifactId>alarm-service</artifactId>
<name>alarm-service</name>
<description>Server side implementation of the service.</description>
<dependencies>
<dependency>
<artifactId>base-container</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>alarm-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>alarm-datastore-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>alarm-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-service-local</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<artifactId>alarm-service</artifactId>
<name>alarm-service</name>
<description>Server side implementation of the service.</description>
<dependencies>
<dependency>
<artifactId>base-container</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
</dependencies>
<dependency>
<artifactId>alarm-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>alarm-datastore-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>alarm-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-service-local</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -129,6 +129,24 @@ public class AlarmController {
throw exp;
}
}
@RequestMapping(value = "/forAlarmCode", method = RequestMethod.GET)
public ListOfAlarms getAllForAlarmCode(
@RequestParam Set<AlarmCode> alarmCode,
@RequestParam long createdAfterTimestamp) {
LOG.debug("getAllForAlarmCode({}, {})", alarmCode, createdAfterTimestamp);
try {
List<Alarm> result = alarmDatastore.get(alarmCode, createdAfterTimestamp);
LOG.debug("getAllForAlarmCode({},{}) return {} entries", alarmCode, createdAfterTimestamp, result.size());
ListOfAlarms ret = new ListOfAlarms();
ret.addAll(result);
return ret;
} catch (Exception exp) {
LOG.error("getAllForAlarmCode({},{}) exception ", alarmCode, createdAfterTimestamp, exp);
throw exp;
}
}
@RequestMapping(value = "/forCustomer", method = RequestMethod.GET)
public PaginationResponse<Alarm> getForCustomer(@RequestParam int customerId,

View File

@@ -349,12 +349,6 @@
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-alarms-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>adoption-metrics-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>

View File

@@ -250,12 +250,6 @@
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-alarms-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>adoption-metrics-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>

View File

@@ -336,12 +336,6 @@
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-alarms-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>adoption-metrics-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>

View File

@@ -1,14 +1,11 @@
package com.telecominfraproject.wlan.startuptasks;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

View File

@@ -1,6 +1,6 @@
package com.telecominfraproject.wlan.client.models.events.realtime;
import java.util.Arrays;
import java.net.InetAddress;
import java.util.Objects;
import com.telecominfraproject.wlan.core.model.equipment.MacAddress;
@@ -14,7 +14,7 @@ public class ClientIpAddressEvent extends RealTimeEvent implements HasClientMac
private long sessionId;
private MacAddress clientMacAddress;
private byte[] ipAddr;
private InetAddress ipAddr;
public ClientIpAddressEvent() {
// serialization
@@ -45,11 +45,11 @@ public class ClientIpAddressEvent extends RealTimeEvent implements HasClientMac
this.clientMacAddress = clientMacAddress;
}
public byte[] getIpAddr() {
public InetAddress getIpAddr() {
return ipAddr;
}
public void setIpAddr(byte[] ipAddr) {
public void setIpAddr(InetAddress ipAddr) {
this.ipAddr = ipAddr;
}
@@ -57,8 +57,7 @@ public class ClientIpAddressEvent extends RealTimeEvent implements HasClientMac
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + Arrays.hashCode(this.ipAddr);
result = prime * result + Objects.hash(clientMacAddress, sessionId);
result = prime * result + Objects.hash(ipAddr, clientMacAddress, sessionId);
return result;
}
@@ -74,7 +73,7 @@ public class ClientIpAddressEvent extends RealTimeEvent implements HasClientMac
return false;
}
ClientIpAddressEvent other = (ClientIpAddressEvent) obj;
return Objects.equals(clientMacAddress, other.clientMacAddress) && Arrays.equals(ipAddr, other.ipAddr)
return Objects.equals(clientMacAddress, other.clientMacAddress) && Objects.equals(ipAddr, other.ipAddr)
&& this.sessionId == other.sessionId;
}

View File

@@ -59,8 +59,7 @@
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>base-stream-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>

View File

@@ -3162,6 +3162,14 @@ components:
- wpa2OnlyPSK
- wpa2OnlyRadius
- wep
- wpaEAP
- wpa2EAP
- wpa2OnlyEAP
- wpa3OnlySAE
- wpa3MixedSAE
- wpa3OnlyEAP
- wpa3MixedEAP
- wpa3OnlyEAP192
RadioBasedSsidConfigurationMap:
properties:
@@ -3456,7 +3464,16 @@ components:
$ref: '#/components/schemas/StatusCode'
statusMessage:
type: string
ledStatus:
$ref: '#/components/schemas/LedStatus'
LedStatus:
type: string
enum:
- led_blink
- led_off
- UNKNOWN
StatusCode:
type: string
enum:
@@ -4390,7 +4407,9 @@ components:
- RADIO_CHANNEL
channelNumberStatusDataMap:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
txPowerDataMap:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
#
# Equipment configuration data models
#
@@ -4499,6 +4518,8 @@ components:
type: boolean
forwardMode:
$ref: '#/components/schemas/NetworkForwardMode'
blinkAllLEDs:
type: boolean
radioMap:
$ref: '#/components/schemas/RadioMap'
advancedRadioMap:

View File

@@ -189,7 +189,6 @@
<module>../provisioning-sp</module>
<module>../dashboard-sp</module>
<module>../equipment-alarms-sp</module>
<module>../adoption-metrics-sp</module>
<module>../single-process-streams</module>

View File

@@ -1 +0,0 @@
/target/

View File

@@ -1,111 +0,0 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<artifactId>equipment-alarms-sp</artifactId>
<name>equipment-alarms-sp</name>
<description>Stream Processors for raising/clearing equipment alarms based on reported metrics.</description>
<dependencies>
<dependency>
<artifactId>base-stream-consumer</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>service-metric-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>system-event-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>alarm-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>status-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<!-- unit tests dependencies -->
<dependency>
<artifactId>single-process-streams</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>alarm-service-local</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>status-service-local</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-service-local</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>alarm-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>status-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,187 +0,0 @@
package com.telecominfraproject.wlan.streams.equipmentalarms;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.telecominfraproject.wlan.alarm.models.Alarm;
import com.telecominfraproject.wlan.alarm.models.AlarmCode;
import com.telecominfraproject.wlan.servicemetric.apnode.models.ApNodeMetrics;
/**
* <br>This context keeps track of information needed for raising/clearing the alarms with the following codes:
* <ul>
* <li>AlarmCode.CPUTemperature
* <li>AlarmCode.CPUUtilization
* <li>AlarmCode.MemoryUtilization
* <li>AlarmCode.NoMetricsReceived
* </ul>
*
* @author dtop
*/
public class EquipmentAlarmsContext {
private final int customerId;
private final long equipmentId;
private final Map<AlarmCode, Alarm> existingAlarms = new ConcurrentHashMap<>();
private final long timeBucketMs;
private final int temperatureThresholdInC;
private final int cpuUtilThresholdPct;
private final int memoryUtilThresholdPct;
private final Map<Long, Integer> cpuTempSamples = new ConcurrentHashMap<>();
private final Map<Long, Integer> cpuUtilSamples = new ConcurrentHashMap<>();
private final Map<Long, Integer> memoryUtilSamples = new ConcurrentHashMap<>();
private final Map<Long, Long> metricReceivedTimestamps = new ConcurrentHashMap<>();
private long totalAvailableMemoryKb;
private final long contextCreationTimestampMs = System.currentTimeMillis();
public EquipmentAlarmsContext(int customerId, long equipmentId, List<Alarm> existingAlarmsList, long timeBucketMs, int temperatureThresholdInC, int cpuUtilThresholdPct, int memoryUtilThresholdPct) {
this.customerId = customerId;
this.equipmentId = equipmentId;
existingAlarmsList.forEach(a -> this.existingAlarms.put(a.getAlarmCode(), a));
this.timeBucketMs = timeBucketMs;
this.temperatureThresholdInC = temperatureThresholdInC;
this.cpuUtilThresholdPct = cpuUtilThresholdPct;
this.memoryUtilThresholdPct = memoryUtilThresholdPct;
}
public long getTotalAvailableMemoryKb() {
return totalAvailableMemoryKb;
}
public void setTotalAvailableMemoryKb(long totalAvailableMemoryKb) {
this.totalAvailableMemoryKb = totalAvailableMemoryKb;
}
public int getCustomerId() {
return customerId;
}
public long getEquipmentId() {
return equipmentId;
}
public Map<AlarmCode, Alarm> getExistingAlarms() {
return existingAlarms;
}
public void addDataSamples(long timestamp, ApNodeMetrics model) {
// add new samples
if(model.getApPerformance()!=null ) {
if(model.getApPerformance().getCpuTemperature()!=null) {
cpuTempSamples.put(timestamp, model.getApPerformance().getCpuTemperature());
}
if(model.getApPerformance().getAvgCpuUtilized()!=null) {
cpuUtilSamples.put(timestamp, model.getApPerformance().getAvgCpuUtilized().intValue());
}
if(model.getApPerformance().getFreeMemory()!=null && totalAvailableMemoryKb>0) {
memoryUtilSamples.put(timestamp, 100 - (int) (model.getApPerformance().getFreeMemory() * 100 / totalAvailableMemoryKb));
}
}
//we are using our own timestamp in here in case AP's time is out of sync - we do not want to raise connectivity alarm in that case
Long currentTs = System.currentTimeMillis();
metricReceivedTimestamps.put(currentTs, currentTs);
}
public void removeOldDataSamples() {
// remove samples older than timeBucketMs
long timeThresholdMs = System.currentTimeMillis() - timeBucketMs;
cpuTempSamples.entrySet().removeIf( t -> t.getKey() < timeThresholdMs );
cpuUtilSamples.entrySet().removeIf( t -> t.getKey() < timeThresholdMs );
memoryUtilSamples.entrySet().removeIf( t -> t.getKey() < timeThresholdMs );
metricReceivedTimestamps.entrySet().removeIf( t -> t.getKey() < timeThresholdMs );
}
public boolean isAlarmNeedsToBeRaised(AlarmCode alarmCode) {
if(existingAlarms.containsKey(alarmCode) || System.currentTimeMillis() < contextCreationTimestampMs + timeBucketMs) {
//no need to check for thresholds - alarm is either already present, or it is too early to tell because the first time bucket has not been filled yet
return false;
}
boolean ret = false;
AtomicInteger sum = new AtomicInteger();
AtomicInteger count = new AtomicInteger();
//check alarms against thresholds
if(alarmCode.getId() == AlarmCode.NoMetricsReceived.getId()) {
ret = metricReceivedTimestamps.isEmpty();
} else if(alarmCode.getId() == AlarmCode.CPUTemperature.getId()) {
cpuTempSamples.values().forEach(v -> { sum.addAndGet(v); count.incrementAndGet(); });
if(count.get() > 0) {
int avg = sum.get() / count.get();
ret = avg >= temperatureThresholdInC ;
}
} else if(alarmCode.getId() == AlarmCode.CPUUtilization.getId()) {
cpuUtilSamples.values().forEach(v -> { sum.addAndGet(v); count.incrementAndGet(); });
if(count.get() > 0) {
int avg = sum.get() / count.get();
ret = avg >= cpuUtilThresholdPct ;
}
} else if(alarmCode.getId() == AlarmCode.MemoryUtilization.getId()) {
memoryUtilSamples.values().forEach(v -> { sum.addAndGet(v); count.incrementAndGet(); });
if(count.get() > 0) {
int avg = sum.get() / count.get();
ret = avg >= memoryUtilThresholdPct ;
}
}
return ret;
}
public boolean isAlarmNeedsToBeCleared(AlarmCode alarmCode) {
if(!existingAlarms.containsKey(alarmCode) || System.currentTimeMillis() < contextCreationTimestampMs + timeBucketMs) {
//no need to check for thresholds - alarm is either not present, or it is too early to tell because the first time bucket has not been filled yet
return false;
}
boolean ret = false;
AtomicInteger sum = new AtomicInteger();
AtomicInteger count = new AtomicInteger();
//check alarms against thresholds
if(alarmCode.getId() == AlarmCode.NoMetricsReceived.getId()) {
ret = !metricReceivedTimestamps.isEmpty();
} else if(alarmCode.getId() == AlarmCode.CPUTemperature.getId()) {
cpuTempSamples.values().forEach(v -> { sum.addAndGet(v); count.incrementAndGet(); });
if(count.get() > 0) {
int avg = sum.get() / count.get();
ret = avg < temperatureThresholdInC ;
} else {
//no new data available, but the alarm exists -> clear the alarm
ret = true;
}
} else if(alarmCode.getId() == AlarmCode.CPUUtilization.getId()) {
cpuUtilSamples.values().forEach(v -> { sum.addAndGet(v); count.incrementAndGet(); });
if(count.get() > 0) {
int avg = sum.get() / count.get();
ret = avg < cpuUtilThresholdPct ;
} else {
//no new data available, but the alarm exists -> clear the alarm
ret = true;
}
} else if(alarmCode.getId() == AlarmCode.MemoryUtilization.getId()) {
memoryUtilSamples.values().forEach(v -> { sum.addAndGet(v); count.incrementAndGet(); });
if(count.get() > 0) {
int avg = sum.get() / count.get();
ret = avg < memoryUtilThresholdPct ;
} else {
//no new data available, but the alarm exists -> clear the alarm
ret = true;
}
}
return ret;
}
}

View File

@@ -1,322 +0,0 @@
package com.telecominfraproject.wlan.streams.equipmentalarms;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.telecominfraproject.wlan.alarm.AlarmServiceInterface;
import com.telecominfraproject.wlan.alarm.models.Alarm;
import com.telecominfraproject.wlan.alarm.models.AlarmCode;
import com.telecominfraproject.wlan.alarm.models.AlarmDetails;
import com.telecominfraproject.wlan.alarm.models.AlarmScopeType;
import com.telecominfraproject.wlan.alarm.models.OriginatorType;
import com.telecominfraproject.wlan.core.model.json.BaseJsonModel;
import com.telecominfraproject.wlan.core.model.streams.QueuedStreamMessage;
import com.telecominfraproject.wlan.equipment.EquipmentServiceInterface;
import com.telecominfraproject.wlan.equipment.models.Equipment;
import com.telecominfraproject.wlan.servicemetric.apnode.models.ApNodeMetrics;
import com.telecominfraproject.wlan.servicemetric.models.ServiceMetric;
import com.telecominfraproject.wlan.servicemetric.models.ServiceMetricDetails;
import com.telecominfraproject.wlan.status.StatusServiceInterface;
import com.telecominfraproject.wlan.status.equipment.report.models.OperatingSystemPerformance;
import com.telecominfraproject.wlan.status.models.Status;
import com.telecominfraproject.wlan.status.models.StatusCode;
import com.telecominfraproject.wlan.status.models.StatusDataType;
import com.telecominfraproject.wlan.stream.StreamProcessor;
/**
* @author dtop
* <br> This stream processor is listening for APNodeMetrics, aggregating them in sliding windows of 5 minutes and raising/clearing alarms based on preconfigured thresholds.
* <br> "No metrics received" alarm is raised when no APNodeMetrics have been received for the equipment in the last interval, cleared when APNodeMetrics appear again
* <br> "Temperature too high" alarm is raised when average temperature over the last interval goes above the configured threshold of 80C, cleared when average temperature goes below the threshold
* <br> "CPU utilization is too high" alarm is raised when average CPU utilization on AP over the last interval goes above the configured threshold of 80%, cleared when average CPU utilization goes below the threshold
* <br> "Memory utilization is too high" alarm is raised when average RAM utilization on AP over the last interval goes above the configured threshold of 70%, cleared when average RAM utilization goes below the threshold
*
*/
@Component
public class EquipmentAlarmsProcessor extends StreamProcessor {
private static final Logger LOG = LoggerFactory.getLogger(EquipmentAlarmsProcessor.class);
@Value("${tip.wlan.wlanServiceMetricsTopic:wlan_service_metrics}")
private String wlanServiceMetricsTopic;
@Value("${tip.wlan.equipmentAlarmProcessor.timeBucketMs:300000}") //5 minutes aggregation buckets
private long timeBucketMs;
@Value("${tip.wlan.equipmentAlarmProcessor.checkAlarmsIntervalMs:15000}") //check for raising/clearing alarms every 15 seconds
private long checkAlarmsIntervalMs;
@Value("${tip.wlan.equipmentAlarmProcessor.temperatureThresholdInC:80}")
private int temperatureThresholdInC;
@Value("${tip.wlan.equipmentAlarmProcessor.cpuUtilThresholdPct:80}")
private int cpuUtilThresholdPct;
@Value("${tip.wlan.equipmentAlarmProcessor.memoryUtilThresholdPct:70}")
private int memoryUtilThresholdPct;
private final ConcurrentHashMap<Long, EquipmentAlarmsContext> contextPerEquipmentIdMap = new ConcurrentHashMap<>();
private final Set<AlarmCode> alarmCodeSet = new HashSet<>();
@Autowired
private AlarmServiceInterface alarmServiceInterface;
@Autowired
private StatusServiceInterface statusServiceInterface;
@Autowired
private EquipmentServiceInterface equipmentServiceInterface;
@Override
protected boolean acceptMessage(QueuedStreamMessage message) {
boolean ret = message.getTopic().equals(wlanServiceMetricsTopic);
if(ret && ( message.getModel() instanceof ServiceMetric) ) {
ServiceMetric sm = (ServiceMetric) message.getModel();
ret = ret &&
(
sm.getDetails() instanceof ApNodeMetrics
);
} else {
ret = false;
}
LOG.trace("acceptMessage {}", ret);
return ret;
}
@Override
protected void processMessage(QueuedStreamMessage message) {
ServiceMetric mdl = (ServiceMetric) message.getModel();
ServiceMetricDetails smd = mdl.getDetails();
LOG.debug("Processing {}", mdl);
switch ( smd.getClass().getSimpleName() ) {
case "ApNodeMetrics":
process(mdl.getCustomerId(), mdl.getCreatedTimestamp(), mdl.getEquipmentId(), (ApNodeMetrics) smd);
break;
default:
process(mdl);
}
}
private void process(int customerId, long timestamp, long equipmentId, ApNodeMetrics model) {
LOG.debug("Processing ApNodeMetrics");
//get context for the equipmentId
EquipmentAlarmsContext context = contextPerEquipmentIdMap.get(equipmentId);
if(context == null) {
//When creating EquipmentAlarmsContext - read currently raised alarms of the types we're interested, keep it in memory.
//Only this SP is responsible for raising/clearing those alarms for this particular equipment
List<Alarm> existingAlarms = alarmServiceInterface.get(customerId, Collections.singleton(equipmentId), alarmCodeSet);
//All alarms that are handled by this stream processor logically exist only once-per-alarmCode-per-equipment.
//Ensure that there is only one alarm per alarmCode per equipment (the latest one), remove all others.
//This is needed to recover from some corner-case scenarios that can happen with the distributed datastores (for example split-brain).
existingAlarms = cleanUpDuplicateAlarms(existingAlarms);
context = new EquipmentAlarmsContext(customerId, equipmentId, existingAlarms, timeBucketMs, temperatureThresholdInC, cpuUtilThresholdPct, memoryUtilThresholdPct);
context = contextPerEquipmentIdMap.putIfAbsent(equipmentId, context);
if(context == null) {
context = contextPerEquipmentIdMap.get(equipmentId);
}
}
//find out TotalAvailableMemory in kb, which is available as part of the OperatingSystemPerformance status object
//we look for it separately because this status may not be populated when the first service_metrics_collection_config are coming in
if(context.getTotalAvailableMemoryKb()==0L) {
Status osPerformanceStatus = statusServiceInterface.getOrNull(customerId, equipmentId, StatusDataType.OS_PERFORMANCE);
if(osPerformanceStatus!=null) {
OperatingSystemPerformance osPerformance = (OperatingSystemPerformance) osPerformanceStatus.getDetails();
if(osPerformance !=null && osPerformance.getTotalAvailableMemoryKb() > 0) {
context.setTotalAvailableMemoryKb(osPerformance.getTotalAvailableMemoryKb());
}
}
}
// Update counters on the context
context.addDataSamples(timestamp, model);
LOG.debug("Processed {}", model);
}
private List<Alarm> cleanUpDuplicateAlarms(List<Alarm> existingAlarms) {
Map<AlarmCode, Alarm> alarmsToKeep= new HashMap<>();
//find out the latest existing alarms for each alarmCode
existingAlarms.forEach(a -> {
Alarm eA = alarmsToKeep.get(a.getAlarmCode());
if(eA == null) {
eA = a;
alarmsToKeep.put(a.getAlarmCode(), a);
}
if(eA.getCreatedTimestamp() < a.getCreatedTimestamp() ) {
alarmsToKeep.put(a.getAlarmCode(), a);
}
});
List<Alarm> alarmsToRemove = new ArrayList<>(existingAlarms);
alarmsToRemove.removeAll(alarmsToKeep.values());
alarmsToRemove.forEach(a -> {
try {
alarmServiceInterface.delete(a.getCustomerId(), a.getEquipmentId(), a.getAlarmCode(), a.getCreatedTimestamp());
} catch(Exception e) {
LOG.debug("Alarm was already deleted: {}", a);
}
});
return new ArrayList<>(alarmsToKeep.values());
}
private void process(BaseJsonModel model) {
LOG.warn("Unprocessed model: {}", model);
}
@PostConstruct
private void postCreate() {
Thread equipmentAlarmsThread = new Thread( new Runnable() {
@Override
public void run() {
LOG.info("Starting equipmentAlarmsThread");
while(true) {
LOG.trace("Checking if alarms need to be raised");
//take a snapshot of existing contexts for this iteration of alarm checks
List<EquipmentAlarmsContext> contexts = new ArrayList<>(contextPerEquipmentIdMap.values());
HashSet<Long> equipmentIdsFromContexts = new HashSet<>();
contexts.forEach(ctx -> equipmentIdsFromContexts.add(ctx.getEquipmentId()));
//get a list of equipment records for the current contexts
HashSet<Long> existingEquipmentIds = new HashSet<>();
try {
List<Equipment> existingEquipment = equipmentServiceInterface.get(equipmentIdsFromContexts);
existingEquipment.forEach(e -> existingEquipmentIds.add(e.getId()));
} catch(Exception e) {
LOG.error("Error when retrieving existing equipment", e);
sleep(checkAlarmsIntervalMs);
continue;
}
for(EquipmentAlarmsContext context : contexts ) {
if(!existingEquipmentIds.contains(context.getEquipmentId())) {
//equipment was removed, let's delete the context and remove all existing alarms for that equipmentId
try {
contextPerEquipmentIdMap.remove(context.getEquipmentId());
alarmServiceInterface.delete(context.getCustomerId(), context.getEquipmentId());
} catch(Exception e) {
LOG.error("Error when removing stale alarms for deleted equipment", e);
}
//nothing else to do for this context
continue;
}
context.removeOldDataSamples();
alarmCodeSet.forEach(alarmCode -> {
try {
//check alarms against thresholds
//if alarm needs to be raised - check if it is currently present, and if not - raise it, and add it to the context
if(context.isAlarmNeedsToBeRaised(alarmCode)) {
Alarm alarm = new Alarm();
alarm.setCustomerId(context.getCustomerId());
alarm.setEquipmentId(context.getEquipmentId());
alarm.setAlarmCode(alarmCode);
alarm.setOriginatorType(OriginatorType.AP);
alarm.setSeverity(alarmCode.getSeverity());
alarm.setScopeType(AlarmScopeType.EQUIPMENT);
alarm.setScopeId("" + context.getEquipmentId());
AlarmDetails alarmDetails = new AlarmDetails();
alarmDetails.setMessage(alarmCode.getDescription());
alarmDetails.setAffectedEquipmentIds(Collections.singletonList(context.getEquipmentId()));
alarm.setDetails(alarmDetails);
alarm = alarmServiceInterface.create(alarm);
context.getExistingAlarms().put(alarmCode, alarm);
}
if(context.isAlarmNeedsToBeCleared(alarmCode)) {
//if alarm needs to be cleared - check if it is currently present, and if it is - clear it, and remove it from the context
Alarm alarm = context.getExistingAlarms().remove(alarmCode);
if(alarm!=null) {
//All alarms that are handled by this stream processor logically exist only once-per-alarmCode-per-equipment.
//In order to self-heal from the corner cases with the datastore where more than one alarm with the same alarmCode
// is raised per equipment (for example when the datastore experienced a split-brain scenario), we would remove
// all alarms with the specified alarmCode for this equipment.
//Most of the time the existingAlarms list below would contain only one alarm.
//
List<Alarm> existingAlarms = alarmServiceInterface.get(alarm.getCustomerId(), Collections.singleton(alarm.getEquipmentId()), Collections.singleton(alarmCode));
existingAlarms.forEach(a -> {
try {
alarmServiceInterface.delete(a.getCustomerId(), a.getEquipmentId(), a.getAlarmCode(), a.getCreatedTimestamp());
} catch(Exception e) {
LOG.debug("Alarm was already deleted: {}", alarm);
}
});
}
}
} catch(Exception e) {
LOG.error("Error when processing context for customer {}", context.getCustomerId(), e);
}
});
}
LOG.trace("Done alarms check");
sleep(checkAlarmsIntervalMs);
}
}
}, "equipmentAlarmsThread");
equipmentAlarmsThread.setDaemon(true);
equipmentAlarmsThread.start();
//populate alarm codes this SP is responsible for
alarmCodeSet.add(AlarmCode.NoMetricsReceived);
alarmCodeSet.add(AlarmCode.CPUTemperature);
alarmCodeSet.add(AlarmCode.CPUUtilization);
alarmCodeSet.add(AlarmCode.MemoryUtilization);
}
private static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

View File

@@ -1,342 +0,0 @@
package com.telecominfraproject.wlan.streams.equipmentalarms;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner;
import com.telecominfraproject.wlan.alarm.AlarmServiceInterface;
import com.telecominfraproject.wlan.alarm.AlarmServiceLocal;
import com.telecominfraproject.wlan.alarm.controller.AlarmController;
import com.telecominfraproject.wlan.alarm.datastore.inmemory.AlarmDatastoreInMemory;
import com.telecominfraproject.wlan.alarm.models.Alarm;
import com.telecominfraproject.wlan.alarm.models.AlarmCode;
import com.telecominfraproject.wlan.cloudeventdispatcher.CloudEventDispatcherEmpty;
import com.telecominfraproject.wlan.core.model.equipment.EquipmentType;
import com.telecominfraproject.wlan.equipment.EquipmentServiceInterface;
import com.telecominfraproject.wlan.equipment.EquipmentServiceLocal;
import com.telecominfraproject.wlan.equipment.controller.EquipmentController;
import com.telecominfraproject.wlan.equipment.datastore.inmemory.EquipmentDatastoreInMemory;
import com.telecominfraproject.wlan.equipment.models.Equipment;
import com.telecominfraproject.wlan.servicemetric.apnode.models.ApNodeMetrics;
import com.telecominfraproject.wlan.servicemetric.apnode.models.ApPerformance;
import com.telecominfraproject.wlan.servicemetric.models.ServiceMetric;
import com.telecominfraproject.wlan.status.StatusServiceLocal;
import com.telecominfraproject.wlan.status.controller.StatusController;
import com.telecominfraproject.wlan.status.datastore.inmemory.StatusDatastoreInMemory;
import com.telecominfraproject.wlan.stream.StreamInterface;
import com.telecominfraproject.wlan.stream.StreamMessageDispatcher;
import com.telecominfraproject.wlan.streams.simple.SimpleStreamsConfig;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = EquipmentAlarmsProcessor.class)
@Import(value = { EquipmentAlarmsProcessor.class, SimpleStreamsConfig.class, StreamMessageDispatcher.class,
AlarmServiceLocal.class, AlarmController.class, AlarmDatastoreInMemory.class,
StatusServiceLocal.class, StatusController.class, StatusDatastoreInMemory.class,
EquipmentServiceLocal.class, EquipmentController.class, EquipmentDatastoreInMemory.class,
CloudEventDispatcherEmpty.class,
//EquipmentAlarmsProcessorTests.Config.class,
})
@Ignore("make these tests more robust, there are intermittent failures")
/*
expected: <0> but was: <1>
org.opentest4j.AssertionFailedError: expected: <0> but was: <1>
at com.telecominfraproject.wlan.streams.equipmentalarms.EquipmentAlarmsProcessorTests.testAccessPointIsUnreachableAlarm(EquipmentAlarmsProcessorTests.java:313)
*/
public class EquipmentAlarmsProcessorTests {
private static final long testTimeBucketMs = 200;
private static final long testCheckAlarmsIntervalMs = 50;
static {
System.setProperty("tip.wlan.equipmentAlarmProcessor.checkAlarmsIntervalMs", "" + testCheckAlarmsIntervalMs);
System.setProperty("tip.wlan.equipmentAlarmProcessor.timeBucketMs", "" + testTimeBucketMs);
}
@Autowired @Qualifier("metricStreamInterface")
StreamInterface<ServiceMetric> metricStreamInterface;
@Autowired
EquipmentAlarmsProcessor equipmentAlarmsProcessor;
@Autowired
AlarmServiceInterface alarmService;
@Autowired
EquipmentServiceInterface equipmentService;
protected static final AtomicLong testSequence = new AtomicLong(1);
@Configuration
public static class Config {
//Another way of configuring dependencies (instead of mentioning them in the pom.xml with the test scope) :
// @Bean
// AlarmServiceInterface getAlarmServiceInterface() {
// return new AlarmServiceInterface() {
// ...
// };
// }
// @Bean
// StatusServiceInterface getStatusServiceInterface() {
// return new StatusServiceInterface() {
// ...
// };
// }
}
@Test
public void testCPUTemperatureAlarm() {
int customerId = getNextCustomerId();
Equipment equipment = new Equipment();
equipment.setCustomerId(customerId);
equipment.setEquipmentType(EquipmentType.AP);
equipment.setInventoryId("testCPUTemperatureAlarm");
equipment.setName(equipment.getInventoryId());
equipment = equipmentService.create(equipment);
long equipmentId = equipment.getId();
ServiceMetric record = new ServiceMetric(customerId , equipmentId );
//create metric a bit in the future so that it gets picked up by the processor and not simply discarded
record.setCreatedTimestamp(System.currentTimeMillis() + 2 * testTimeBucketMs);
ApNodeMetrics apNodeMetrics = new ApNodeMetrics();
record.setDetails(apNodeMetrics);
ApPerformance apPerformance = new ApPerformance();
apNodeMetrics.setApPerformance(apPerformance);
//we will force the CPUTemperature alarm to be raised
apPerformance.setCpuTemperature(85);
apPerformance.setCpuUtilized(new int[] { 70, 70 });
apPerformance.setFreeMemory(30000000);
//publish metric that should trigger alarm for the CPU Temperature
metricStreamInterface.publish(record );
//wait for the metric to be processed
sleep(2 * testTimeBucketMs);
//verify that alarm was raised
List<Alarm> alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.CPUTemperature));
assertEquals(1, alarms.size());
//Now create a metric that should clear the alarm
ServiceMetric recordToClearAlarm = record.clone();
recordToClearAlarm.setCreatedTimestamp(System.currentTimeMillis() + 2* testTimeBucketMs );
((ApNodeMetrics)recordToClearAlarm.getDetails()).getApPerformance().setCpuTemperature(70);
//publish metric that should clear the alarm for the CPU Temperature
metricStreamInterface.publish(recordToClearAlarm);
//wait for the metric to be processed
sleep(2 * testTimeBucketMs);
//verify that alarm was cleared
alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.CPUTemperature));
assertEquals(0, alarms.size());
}
@Test
public void testCPUTemperatureAlarm_NoEquipment() {
int customerId = getNextCustomerId();
long equipmentId = -5;
ServiceMetric record = new ServiceMetric(customerId , equipmentId );
//create metric a bit in the future so that it gets picked up by the processor and not simply discarded
record.setCreatedTimestamp(System.currentTimeMillis() + 2 * testTimeBucketMs);
ApNodeMetrics apNodeMetrics = new ApNodeMetrics();
record.setDetails(apNodeMetrics);
ApPerformance apPerformance = new ApPerformance();
apNodeMetrics.setApPerformance(apPerformance);
//we will force the CPUTemperature alarm to be raised
apPerformance.setCpuTemperature(85);
apPerformance.setCpuUtilized(new int[] { 70, 70 });
apPerformance.setFreeMemory(30000000);
//publish metric that should trigger alarm for the CPU Temperature
metricStreamInterface.publish(record );
//wait for the metric to be processed
sleep(2 * testTimeBucketMs);
//verify that alarm was not raised - because equipment for that alarm does not exist
List<Alarm> alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.CPUTemperature));
assertEquals(0, alarms.size());
}
@Test
public void testCPUUtilizationAlarm() {
int customerId = getNextCustomerId();
Equipment equipment = new Equipment();
equipment.setCustomerId(customerId);
equipment.setEquipmentType(EquipmentType.AP);
equipment.setInventoryId("testCPUUtilizationAlarm");
equipment.setName(equipment.getInventoryId());
equipment = equipmentService.create(equipment);
long equipmentId = equipment.getId();
ServiceMetric record = new ServiceMetric(customerId , equipmentId );
//create metric a bit in the future so that it gets picked up by the processor and not simply discarded
record.setCreatedTimestamp(System.currentTimeMillis() + 2 * testTimeBucketMs);
ApNodeMetrics apNodeMetrics = new ApNodeMetrics();
record.setDetails(apNodeMetrics);
ApPerformance apPerformance = new ApPerformance();
apNodeMetrics.setApPerformance(apPerformance);
apPerformance.setCpuTemperature(55);
//we will force the CPUUtilization alarm to be raised
apPerformance.setCpuUtilized(new int[] { 90, 90 });
apPerformance.setFreeMemory(30000000);
//publish metric that should trigger alarm for the CPU Utilization
metricStreamInterface.publish(record );
//wait for the metric to be processed
sleep(2 * testTimeBucketMs);
//verify that alarm was raised
List<Alarm> alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.CPUUtilization));
assertEquals(1, alarms.size());
//Now create a metric that should clear the alarm
ServiceMetric recordToClearAlarm = record.clone();
recordToClearAlarm.setCreatedTimestamp(System.currentTimeMillis() + 2* testTimeBucketMs );
((ApNodeMetrics)recordToClearAlarm.getDetails()).getApPerformance().setCpuUtilized(new int[] { 50, 50 });
//publish metric that should clear the alarm for the CPU Utilization
metricStreamInterface.publish(recordToClearAlarm);
//wait for the metric to be processed
sleep(2 * testTimeBucketMs);
//verify that alarm was cleared
alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.CPUUtilization));
assertEquals(0, alarms.size());
}
@Test
public void testAccessPointIsUnreachableAlarm() {
int customerId = getNextCustomerId();
Equipment equipment = new Equipment();
equipment.setCustomerId(customerId);
equipment.setEquipmentType(EquipmentType.AP);
equipment.setInventoryId("testAccessPointIsUnreachableAlarm");
equipment.setName(equipment.getInventoryId());
equipment = equipmentService.create(equipment);
long equipmentId = equipment.getId();
ServiceMetric record = new ServiceMetric(customerId , equipmentId );
//create metric a bit in the future so that it gets picked up by the processor and not simply discarded
record.setCreatedTimestamp(System.currentTimeMillis() + testTimeBucketMs);
ApNodeMetrics apNodeMetrics = new ApNodeMetrics();
record.setDetails(apNodeMetrics);
ApPerformance apPerformance = new ApPerformance();
apNodeMetrics.setApPerformance(apPerformance);
apPerformance.setCpuTemperature(55);
//we will force the CPUUtilization alarm to be raised
apPerformance.setCpuUtilized(new int[] { 50, 50 });
apPerformance.setFreeMemory(30000000);
//publish metric that should not trigger AccessPointIsUnreachable alarm
metricStreamInterface.publish(record );
//wait for the metric to be processed
sleep(testTimeBucketMs);
//verify that alarm was not raised
List<Alarm> alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.AccessPointIsUnreachable));
assertEquals(0, alarms.size());
//Now wait for the alarm to be raised because no service_metrics_collection_config were posted
sleep(testTimeBucketMs);
//verify that alarm was raised
for(int i = 0; i < 50; i++) {
alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.AccessPointIsUnreachable));
if(!alarms.isEmpty()) {
break;
}else {
sleep(5);
}
}
assertEquals(1, alarms.size());
//Now create a metric that should clear the alarm
ServiceMetric recordToClearAlarm = record.clone();
recordToClearAlarm.setCreatedTimestamp(System.currentTimeMillis() + testTimeBucketMs );
//publish metric that should clear the AccessPointIsUnreachable alarm
metricStreamInterface.publish(recordToClearAlarm);
//wait for the metric to be processed
sleep(testTimeBucketMs);
//verify that alarm was cleared
for(int i = 0; i < 50; i++) {
alarms = alarmService.get(customerId, Collections.singleton(equipmentId), Collections.singleton(AlarmCode.AccessPointIsUnreachable));
if(alarms.isEmpty()) {
break;
}else {
sleep(5);
}
}
assertEquals(0, alarms.size());
}
public int getNextCustomerId() {
return (int) testSequence.incrementAndGet();
}
public long getNextEquipmentId() {
return testSequence.incrementAndGet();
}
public void sleep(long ms) {
try {
Thread.sleep( ms );
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<conversionRule conversionWord="filteredStack"
converterClass="com.telecominfraproject.wlan.server.exceptions.logback.ExceptionCompressingConverter" />
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%filteredStack%nopex</pattern>
<!-- See http://logback.qos.ch/manual/layouts.html for details -->
<!-- %ex{5} - add at the end to display only 5 levels of the exception stack trace -->
<!-- %nopex - add at the end to not display any of the exception stack traces -->
<!-- %ex{full} - add at the end to display all the levels of the exception stack trace -->
</encoder>
</appender>
<!--
details: http://logback.qos.ch/manual/configuration.html#auto_configuration
runtime configuration, if need to override the defaults:
-Dlogging.config=file:///home/ec2-user/opensync/logback.xml
for log configuration debugging - use
-Dlogback.statusListenerClass=ch.qos.logback.core.status.OnConsoleStatusListener
log levels:
OFF ERROR WARN INFO DEBUG TRACE
-->
<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
<logger name="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" level="INFO"/>
<logger name="org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer" level="INFO"/>
<logger name="org.springframework.security.web.authentication.preauth" level="OFF"/>
<logger name="com.netflix.servo.tag.aws.AwsInjectableTag" level="OFF"/>
<logger name="com.telecominfraproject" level="WARN"/>
<!--
<logger name="com.telecominfraproject.wlan.streams.simple" level="TRACE"/>
<logger name="com.telecominfraproject.wlan.streams.equipmentalarms" level="TRACE"/>
-->
<root level="WARN">
<appender-ref ref="stdout"/>
</root>
</configuration>

View File

@@ -37,6 +37,7 @@ public abstract class CommonElementConfiguration extends EquipmentDetails implem
private AntennaType antennaType;
private Boolean costSavingEventsEnabled;
private NetworkForwardMode forwardMode;
private boolean blinkAllLEDs;
/**
* this constructor is used for CAMI only
@@ -69,37 +70,33 @@ public abstract class CommonElementConfiguration extends EquipmentDetails implem
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + Objects.hash(antennaType, blinkAllLEDs, costSavingEventsEnabled, deploymentType, deviceMode, deviceName, elementConfigVersion,
equipmentType, forwardMode, frameReportThrottleEnabled, gettingDNS, gettingIP, locallyConfigured, locallyConfiguredMgmtVlan, locationData,
peerInfoList, staticDnsIp1, staticDnsIp2, staticIP, staticIpGw, staticIpMaskCidr, syntheticClientEnabled);
return result;
}
if (!super.equals(obj)) {
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
}
if (!(obj instanceof CommonElementConfiguration)) {
if (getClass() != obj.getClass())
return false;
}
CommonElementConfiguration other = (CommonElementConfiguration) obj;
return this.antennaType == other.antennaType
&& Objects.equals(costSavingEventsEnabled, other.costSavingEventsEnabled)
&& this.deploymentType == other.deploymentType && this.deviceMode == other.deviceMode
&& Objects.equals(deviceName, other.deviceName)
&& Objects.equals(elementConfigVersion, other.elementConfigVersion)
&& this.equipmentType == other.equipmentType && this.forwardMode == other.forwardMode
&& Objects.equals(frameReportThrottleEnabled, other.frameReportThrottleEnabled)
&& this.gettingDNS == other.gettingDNS && this.gettingIP == other.gettingIP
&& this.locallyConfigured == other.locallyConfigured
&& this.locallyConfiguredMgmtVlan == other.locallyConfiguredMgmtVlan
&& Objects.equals(locationData, other.locationData) && Objects.equals(peerInfoList, other.peerInfoList)
&& Objects.equals(staticDnsIp1, other.staticDnsIp1) && Objects.equals(staticDnsIp2, other.staticDnsIp2)
&& Objects.equals(staticIP, other.staticIP) && Objects.equals(staticIpGw, other.staticIpGw)
&& Objects.equals(staticIpMaskCidr, other.staticIpMaskCidr)
&& Objects.equals(syntheticClientEnabled, other.syntheticClientEnabled);
return antennaType == other.antennaType && blinkAllLEDs == other.blinkAllLEDs && Objects.equals(costSavingEventsEnabled, other.costSavingEventsEnabled)
&& deploymentType == other.deploymentType && deviceMode == other.deviceMode && Objects.equals(deviceName, other.deviceName)
&& Objects.equals(elementConfigVersion, other.elementConfigVersion) && Objects.equals(equipmentType, other.equipmentType)
&& forwardMode == other.forwardMode && Objects.equals(frameReportThrottleEnabled, other.frameReportThrottleEnabled)
&& gettingDNS == other.gettingDNS && gettingIP == other.gettingIP && locallyConfigured == other.locallyConfigured
&& locallyConfiguredMgmtVlan == other.locallyConfiguredMgmtVlan && Objects.equals(locationData, other.locationData)
&& Objects.equals(peerInfoList, other.peerInfoList) && Objects.equals(staticDnsIp1, other.staticDnsIp1)
&& Objects.equals(staticDnsIp2, other.staticDnsIp2) && Objects.equals(staticIP, other.staticIP) && Objects.equals(staticIpGw, other.staticIpGw)
&& Objects.equals(staticIpMaskCidr, other.staticIpMaskCidr) && Objects.equals(syntheticClientEnabled, other.syntheticClientEnabled);
}
public AntennaType getAntennaType() {
@@ -189,14 +186,6 @@ public abstract class CommonElementConfiguration extends EquipmentDetails implem
return syntheticClientEnabled;
}
@Override
public int hashCode() {
return Objects.hash(antennaType, costSavingEventsEnabled, deploymentType, deviceMode, deviceName,
elementConfigVersion, equipmentType, forwardMode, frameReportThrottleEnabled, gettingDNS, gettingIP,
locallyConfigured, locallyConfiguredMgmtVlan, locationData, peerInfoList, staticDnsIp1, staticDnsIp2,
staticIP, staticIpGw, staticIpMaskCidr, syntheticClientEnabled);
}
@Override
public boolean hasUnsupportedValue() {
if (super.hasUnsupportedValue()) {
@@ -311,4 +300,14 @@ public abstract class CommonElementConfiguration extends EquipmentDetails implem
public void setSyntheticClientEnabled(Boolean syntheticClientEnabled) {
this.syntheticClientEnabled = syntheticClientEnabled;
}
public boolean isBlinkAllLEDs() {
return blinkAllLEDs;
}
public void setBlinkAllLEDs(boolean blinkAllLEDs) {
this.blinkAllLEDs = blinkAllLEDs;
}
}

View File

@@ -0,0 +1,18 @@
package com.telecominfraproject.wlan.equipment.models.events;
import com.telecominfraproject.wlan.equipment.models.Equipment;
public class EquipmentBlinkLEDsEvent extends EquipmentChangedEvent {
private static final long serialVersionUID = 5222048279956123654L;
public EquipmentBlinkLEDsEvent(Equipment equipment){
super(equipment);
setEquipmentChangeType(EquipmentChangeType.blinkLEDs);
}
/**
* Constructor used by JSON
*/
private EquipmentBlinkLEDsEvent() {
super();
}
}

View File

@@ -10,11 +10,11 @@ import com.telecominfraproject.wlan.core.model.json.JsonDeserializationUtils;
public enum EquipmentChangeType {
All(0), ChannelsOnly(1), CellSizeAttributesOnly(2), ApImpacting(3), UNSUPPORTED(-1);
All(0), ChannelsOnly(1), CellSizeAttributesOnly(2), ApImpacting(3), blinkLEDs(4), CustomerOnly(5), UNSUPPORTED(-1);
private final int id;
private static final Map<Integer, EquipmentChangeType> ELEMENTS = new HashMap<>();
private static final EquipmentChangeType validValues[] = { All, ChannelsOnly, CellSizeAttributesOnly, ApImpacting};
private static final EquipmentChangeType validValues[] = { All, ChannelsOnly, CellSizeAttributesOnly, ApImpacting,blinkLEDs};
private EquipmentChangeType(int id) {
this.id = id;

View File

@@ -0,0 +1,41 @@
package com.telecominfraproject.wlan.equipment.models.events;
import com.telecominfraproject.wlan.equipment.models.Equipment;
public class EquipmentCustomerChangedEvent extends EquipmentChangedEvent {
private static final long serialVersionUID = 4650302079238674307L;
private Equipment existingEquipment; // old equipment
private Equipment equipment; // new configured equipment
public EquipmentCustomerChangedEvent(Equipment existingEquipment, Equipment equipment) {
super(equipment);
setEquipmentChangeType(EquipmentChangeType.CustomerOnly);
this.setExistingEquipment(existingEquipment);
this.setEquipment(equipment);
}
/**
* Constructor used by JSON
*/
@SuppressWarnings("unused")
private EquipmentCustomerChangedEvent() {
super();
}
public Equipment getExistingEquipment() {
return existingEquipment;
}
public void setExistingEquipment(Equipment existingEquipment) {
this.existingEquipment = existingEquipment;
}
public Equipment getEquipment() {
return equipment;
}
public void setEquipment(Equipment equipment) {
this.equipment = equipment;
}
}

View File

@@ -1,57 +1,58 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<artifactId>equipment-service-remote</artifactId>
<name>equipment-service-remote</name>
<description>Remote client for accessing the service, uses REST API calls.</description>
<dependencies>
<dependency>
<artifactId>equipment-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>base-client</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<artifactId>equipment-service-remote</artifactId>
<name>equipment-service-remote</name>
<description>Remote client for accessing the service, uses REST API calls.</description>
<!-- Dependencies for the unit tests -->
<dependency>
<artifactId>base-remote-tests</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-service</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependencies>
<dependency>
<artifactId>equipment-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>base-client</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<!-- Dependencies for the unit tests -->
<dependency>
<artifactId>base-remote-tests</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependency>
<artifactId>equipment-service</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,53 +1,59 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<artifactId>equipment-service</artifactId>
<name>equipment-service</name>
<description>Server side implementation of the service.</description>
<dependencies>
<dependency>
<artifactId>base-container</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-datastore-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<artifactId>equipment-service</artifactId>
<name>equipment-service</name>
<description>Server side implementation of the service.</description>
<dependencies>
<dependency>
<artifactId>alarm-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>base-container</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
</dependencies>
<dependency>
<artifactId>cloud-event-dispatcher-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-datastore-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -47,14 +47,15 @@ import com.telecominfraproject.wlan.equipment.models.SourceSelectionMulticast;
import com.telecominfraproject.wlan.equipment.models.bulkupdate.rrm.EquipmentRrmBulkUpdateRequest;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentAddedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentApImpactingChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentBlinkLEDsEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentCellSizeAttributesChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentChannelsChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentCustomerChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentRemovedEvent;
import com.telecominfraproject.wlan.server.exceptions.ConfigurationException;
import com.telecominfraproject.wlan.systemevent.models.SystemEvent;
/**
* @author dtoptygin
*
@@ -73,7 +74,6 @@ public class EquipmentController {
@Autowired private EquipmentDatastore equipmentDatastore;
@Autowired private CloudEventDispatcherInterface cloudEventDispatcher;
/**
* Creates new Equipment.
*
@@ -280,18 +280,23 @@ public class EquipmentController {
LOG.debug("Updated Equipment {}", ret);
EquipmentChangedEvent event;
if (equipment.getCustomerId() != existingEquipment.getCustomerId()) {
publishEvent(new EquipmentCustomerChangedEvent(existingEquipment, ret));
}
if ((equipment.getProfileId() != existingEquipment.getProfileId()) || (existingApElementConfig != null && updatedApElementConfig != null &&
updatedApElementConfig.needsToBeUpdatedOnDevice(existingApElementConfig))) {
event = new EquipmentApImpactingChangedEvent(ret);
} else if (existingApElementConfig != null && existingApElementConfig.isBlinkAllLEDs() != updatedApElementConfig.isBlinkAllLEDs()) {
LOG.debug("Updated BlinkingLEDs {}", ret);
event = new EquipmentBlinkLEDsEvent(ret);
} else {
event = new EquipmentChangedEvent(ret);
}
publishEvent(event);
return ret;
}
private void validateChannelNum(Equipment equipment) {
if (equipment.getDetails() instanceof ApElementConfiguration) {
ApElementConfiguration apElementConfiguration = (ApElementConfiguration) equipment.getDetails();

View File

@@ -220,6 +220,8 @@ components:
type: boolean
forwardMode:
$ref: '#/components/schemas/NetworkForwardMode'
blinkAllLEDs:
type: boolean
radioMap:
$ref: '#/components/schemas/RadioMap'
advancedRadioMap:

View File

@@ -34,7 +34,7 @@ import com.telecominfraproject.wlan.equipment.models.Equipment;
EquipmentController.class,
CloudEventDispatcherEmpty.class,
EquipmentDatastoreInMemory.class,
EquipmentControllerTest.Config.class,
EquipmentControllerTest.Config.class
})
public class EquipmentControllerTest {

View File

@@ -118,6 +118,49 @@
<version>1.2.0-SNAPSHOT</version>
</dependency>
<!-- test dependencies -->
<dependency>
<artifactId>equipment-service-local</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-service</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>equipment-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>cloud-event-dispatcher-empty</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>profile-service-local</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>profile-service</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>profile-datastore-inmemory</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -158,55 +158,66 @@ public class ProfilePortalController {
}
}
@RequestMapping(value = "/profile/equipmentCounts", method = RequestMethod.GET)
public ListOfPairLongLong getCountsOfEquipmentThatUseProfiles(@RequestParam Set<Long> profileIdSet) {
LOG.debug("getCountsOfEquipmentThatUseProfiles({})", profileIdSet);
//first get top-level profiles for the supplied set - only top-level profiles are linked to equipment
List<PairLongLong> topLevelProfiles = this.profileServiceInterface.getTopLevelProfiles(profileIdSet);
Map<Long, AtomicInteger> profileIdToCountMap = new HashMap<Long, AtomicInteger>();
profileIdSet.forEach(profileId -> profileIdToCountMap.put(profileId, new AtomicInteger(0)));
//Maps child at all top level profiles that reference it. A top level profile references itself int this map
Map<Long, List<Long>> childProfileToTopProfileMap = new HashMap<Long, List<Long>>();
List<PairLongLong> topLevelProfileList = profileServiceInterface.getTopLevelProfiles(profileIdSet);
Set<Long> topProfileIdSet= new HashSet<Long>();
topLevelProfileList.forEach(pair ->
{
if (childProfileToTopProfileMap.putIfAbsent(
pair.getValue1(),
new ArrayList<Long>() {{ add(pair.getValue2());}}
) != null)
{
childProfileToTopProfileMap.compute(pair.getValue1(), (k,v) ->
new ArrayList<Long>() {{
addAll(v);
add(pair.getValue2());}});
}
topProfileIdSet.add(pair.getValue2());
});
Map<Long, AtomicInteger> topProfileToEquipmentCountMap = new HashMap<>();
topProfileIdSet.forEach(p -> topProfileToEquipmentCountMap.put(p, new AtomicInteger()));
PaginationContext<PairLongLong> context = new PaginationContext<>(500);
equipmentServiceInterface.getEquipmentIdsByProfileIds(topProfileIdSet, context);
while(!context.isLastPage()) {
PaginationResponse<PairLongLong> page = equipmentServiceInterface.getEquipmentIdsByProfileIds(topProfileIdSet, context );
context = page.getContext();
page.getItems().forEach(p -> {
AtomicInteger cnt = topProfileToEquipmentCountMap.get(p.getValue1());
if(cnt!=null) {
cnt.incrementAndGet();
}
});
LOG.debug("Page {} - counted {} equipmentids", context.getLastReturnedPageNumber(), context.getTotalItemsReturned());
}
// assemble profile count for return, using child to top level profile id map
childProfileToTopProfileMap.forEach((childKey,TopLevelIdList) ->
{
for (Long topProfileId : TopLevelIdList)
{
profileIdToCountMap.get(childKey).addAndGet(topProfileToEquipmentCountMap.get(topProfileId).get());
}
});
//package results to get equipment counts for the original profile ids
ListOfPairLongLong ret = new ListOfPairLongLong();
profileIdToCountMap.forEach((id, count) -> ret.add(new PairLongLong(id, count.get())));
//map each supplied profile to its top-level parent
Map<Long, Long> profileIdToTopProfileIdMap = new HashMap<>();
topLevelProfiles.forEach(pair -> profileIdToTopProfileIdMap.put(pair.getValue1(), pair.getValue2()));
//gather top-level profile ids
Set<Long> topProfileIds = new HashSet<>();
topLevelProfiles.forEach(pair -> topProfileIds.add(pair.getValue2()));
//TODO: this may be more efficiently done by a specialized count method on equipment datastore
//now get pages of equipmentIds that refer to the top-level profiles and count the equipmentIds
PaginationContext<PairLongLong> context = new PaginationContext<>(500);
this.equipmentServiceInterface.getEquipmentIdsByProfileIds(topProfileIds, context );
//prepare map of top-level profileId to the count of equipmentIds
Map<Long, AtomicInteger> topProfileIdToEquipmentCountsMap = new HashMap<>();
topProfileIds.forEach(p -> topProfileIdToEquipmentCountsMap.put(p, new AtomicInteger()));
while(!context.isLastPage()) {
PaginationResponse<PairLongLong> page = equipmentServiceInterface.getEquipmentIdsByProfileIds(topProfileIds, context );
context = page.getContext();
page.getItems().forEach(p -> {
AtomicInteger cnt = topProfileIdToEquipmentCountsMap.get(p.getValue1());
if(cnt!=null) {
cnt.incrementAndGet();
}
});
LOG.debug("Page {} - counted {} equipmentids", context.getLastReturnedPageNumber(), context.getTotalItemsReturned());
}
//package results to get equipment counts for the original profile ids
profileIdToTopProfileIdMap.forEach((p, tp) -> ret.add(new PairLongLong(p, topProfileIdToEquipmentCountsMap.get(tp).intValue())));
LOG.debug("getCountsOfEquipmentThatUseProfiles({}) return {}", profileIdSet, ret);
return ret;
}
}

View File

@@ -1043,6 +1043,8 @@ components:
type: boolean
forwardMode:
$ref: '#/components/schemas/NetworkForwardMode'
blinkAllLEDs:
type: boolean
radioMap:
$ref: '#/components/schemas/RadioMap'
advancedRadioMap:
@@ -2266,7 +2268,8 @@ components:
- wpa3OnlySAE
- wpa3MixedSAE
- wpa3OnlyEAP
- wpa3MixedEAP
- wpa3MixedEAP
- wpa3OnlyEAP192
RadioBasedSsidConfigurationMap:
properties:
@@ -3330,8 +3333,6 @@ components:
EquipmentAdminStatusData:
type: object
required:
- model_type
properties:
model_type:
type: string
@@ -3345,6 +3346,15 @@ components:
$ref: '#/components/schemas/StatusCode'
statusMessage:
type: string
ledStatus:
$ref: '#/components/schemas/LedStatus'
LedStatus:
type: string
enum:
- led_blink
- led_off
- UNKNOWN
StatusCode:
type: string
@@ -4308,6 +4318,8 @@ components:
- RADIO_CHANNEL
channelNumberStatusDataMap:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
txPowerDataMap:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
#
# Objects related to Client sessions
@@ -9086,6 +9098,7 @@ components:
- EquipmentChangedEvent
- EquipmentApImpactingChangedEvent
- EquipmentChannelsChangedEvent
- EquipmentBlinkLEDsEvent
- EquipmentCellSizeAttributesChangedEvent
- EquipmentRemovedEvent
- StatusChangedEvent
@@ -9179,6 +9192,7 @@ components:
- $ref: '#/components/schemas/EquipmentChangedEvent'
- $ref: '#/components/schemas/EquipmentApImpactingChangedEvent'
- $ref: '#/components/schemas/EquipmentChannelsChangedEvent'
- $ref: '#/components/schemas/EquipmentBlinkLEDsEvent'
- $ref: '#/components/schemas/EquipmentCellSizeAttributesChangedEvent'
- $ref: '#/components/schemas/EquipmentRemovedEvent'
- $ref: '#/components/schemas/StatusChangedEvent'
@@ -9532,7 +9546,12 @@ components:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
newBackupChannels:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
EquipmentBlinkLEDsEvent:
properties:
allOf:
$ref: '#/components/schemas/EquipmentChangedEvent'
EquipmentCellSizeAttributesChangedEvent:
properties:
allOf:

View File

@@ -0,0 +1,200 @@
package com.telecominfraproject.wlan.portal.controller.profile;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import com.telecominfraproject.wlan.cloudeventdispatcher.CloudEventDispatcherEmpty;
import com.telecominfraproject.wlan.core.model.equipment.EquipmentType;
import com.telecominfraproject.wlan.core.model.pair.PairLongLong;
import com.telecominfraproject.wlan.equipment.EquipmentServiceLocal;
import com.telecominfraproject.wlan.equipment.controller.EquipmentController;
import com.telecominfraproject.wlan.equipment.datastore.EquipmentDatastore;
import com.telecominfraproject.wlan.equipment.datastore.inmemory.EquipmentDatastoreInMemory;
import com.telecominfraproject.wlan.equipment.models.Equipment;
import com.telecominfraproject.wlan.portal.controller.profile.ProfilePortalController.ListOfPairLongLong;
import com.telecominfraproject.wlan.profile.ProfileServiceLocal;
import com.telecominfraproject.wlan.profile.controller.ProfileController;
import com.telecominfraproject.wlan.profile.datastore.ProfileDatastore;
import com.telecominfraproject.wlan.profile.datastore.inmemory.ProfileDatastoreInMemory;
import com.telecominfraproject.wlan.profile.models.Profile;
import com.telecominfraproject.wlan.profile.models.ProfileByCustomerRequestFactory;
import com.telecominfraproject.wlan.profile.models.ProfileType;
@RunWith(SpringRunner.class)
@ActiveProfiles(profiles = {
"integration_test",
}) //NOTE: these profiles will be ADDED to the list of active profiles
@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = ProfilePortalControllerTest.class)
@Import(value = {
EquipmentServiceLocal.class,
EquipmentController.class,
EquipmentDatastoreInMemory.class,
ProfileServiceLocal.class,
ProfileController.class,
ProfileDatastoreInMemory.class,
ProfileByCustomerRequestFactory.class,
CloudEventDispatcherEmpty.class,
ProfilePortalController.class
})
public class ProfilePortalControllerTest {
private static AtomicLong profileIncrementer = new AtomicLong(1);
private static AtomicLong equipmentIncrementer = new AtomicLong(1);
private static Set<Long> profileIds = new HashSet<Long>();
private static Set<Long> equipmentIds = new HashSet<Long>();
@Autowired private ProfilePortalController profilePortalController;
@Autowired private EquipmentDatastore equipmentDatastore;
@Autowired private ProfileDatastore profileDatastore;
@BeforeEach
public void setup()
{
profileIds.clear();
equipmentIds.clear();
}
@Test
public void getCountsOfEquipmentThatUseProfilesTest()
{
Profile parentProfile_1 = createProfile(); // 3 equipment
Profile parentProfile_2 = createProfile(); // 2 equipment
Profile parentProfile_3 = createProfile(); // 1 equipment
Profile ssidProfile_1 = createSsidProfile(); // linked to parent ids: 1 = 3 expected count
Profile ssidProfile_2 = createSsidProfile(); // linked to parent ids: 1,2 = 5 expected count
Profile ssidProfile_3 = createSsidProfile(); // linked to parent ids: 3 = 1 expected count
Profile captivePortalProfile_1 = createCaptivePortalProfile(); // linked to 4 -> 1 = 3 expected count
Profile captivePortalProfile_2 = createCaptivePortalProfile(); // linked to 5 and 6 -> 5 + 1 = 6 expected count
Profile radiusProfile_1 = createRadiusProfile(); // 7, 8 -> 4, 5, 6 -> 1 , 2 , 3 -> 6 expected
Profile radiusProfile_2 = createRadiusProfile(); // 0 expected
// link ssid to AP profiles
linkChildToParent(ssidProfile_1.getId(), parentProfile_1.getId());
linkChildToParent(ssidProfile_2.getId(), parentProfile_1.getId());
linkChildToParent(ssidProfile_2.getId(), parentProfile_2.getId());
linkChildToParent(ssidProfile_3.getId(), parentProfile_3.getId());
//link captive portal profiles to ssid profiles
linkChildToParent(captivePortalProfile_1.getId(), ssidProfile_1.getId());
linkChildToParent(captivePortalProfile_2.getId(), ssidProfile_2.getId());
linkChildToParent(captivePortalProfile_2.getId(), ssidProfile_3.getId());
//link radius profiles to captive portal profiles
linkChildToParent(radiusProfile_1.getId(), captivePortalProfile_1.getId());
linkChildToParent(radiusProfile_1.getId(), captivePortalProfile_2.getId());
createEquipment(parentProfile_1.getId());
createEquipment(parentProfile_1.getId());
createEquipment(parentProfile_1.getId());
createEquipment(parentProfile_2.getId());
createEquipment(parentProfile_2.getId());
createEquipment(parentProfile_3.getId());
ListOfPairLongLong ret = profilePortalController.getCountsOfEquipmentThatUseProfiles(profileIds);
List<PairLongLong> expectedReturn = new ArrayList<PairLongLong>() {{
add(new PairLongLong(parentProfile_1.getId(), 3));
add(new PairLongLong(parentProfile_2.getId(), 2));
add(new PairLongLong(parentProfile_3.getId(), 1));
add(new PairLongLong(ssidProfile_1.getId(), 3));
add(new PairLongLong(ssidProfile_2.getId(), 5));
add(new PairLongLong(ssidProfile_3.getId(), 1));
add(new PairLongLong(captivePortalProfile_1.getId(), 3));
add(new PairLongLong(captivePortalProfile_2.getId(), 6));
add(new PairLongLong(radiusProfile_1.getId(), 6));
add(new PairLongLong(radiusProfile_2.getId(), 0));
}};
expectedReturn.forEach(pair -> assertTrue(ret.contains(pair)));
equipmentIds.forEach(id -> equipmentDatastore.delete(id));
profileIds.forEach(id -> profileDatastore.delete(id));
}
private Profile createProfile()
{
Profile profile = new Profile();
profile.setName("test" + profileIncrementer.getAndIncrement());
profile.setProfileType(ProfileType.equipment_ap);
profile.setCustomerId(2);
Profile created = profileDatastore.create(profile);
profileIds.add(created.getId());
return created;
}
private Profile createSsidProfile()
{
Profile profile = new Profile();
profile.setName("test" + profileIncrementer.getAndIncrement());
profile.setProfileType(ProfileType.ssid);
profile.setCustomerId(2);
Profile created = profileDatastore.create(profile);
profileIds.add(created.getId());
return created;
}
private Profile createCaptivePortalProfile()
{
Profile profile = new Profile();
profile.setName("test" + profileIncrementer.getAndIncrement());
profile.setProfileType(ProfileType.captive_portal);
profile.setCustomerId(2);
Profile created = profileDatastore.create(profile);
profileIds.add(created.getId());
return created;
}
private Profile createRadiusProfile()
{
Profile profile = new Profile();
profile.setName("test" + profileIncrementer.getAndIncrement());
profile.setProfileType(ProfileType.radius);
profile.setCustomerId(2);
Profile created = profileDatastore.create(profile);
profileIds.add(created.getId());
return created;
}
private void linkChildToParent(long childId, long parentId)
{
Profile parentProfile = profileDatastore.get(parentId);
parentProfile.getChildProfileIds().add(childId);
profileDatastore.update(parentProfile);
}
private Equipment createEquipment(long profileId)
{
Equipment equipment = new Equipment();
equipment.setCustomerId(2);
equipment.setEquipmentType(EquipmentType.AP);
equipment.setName("test" + equipmentIncrementer.getAndIncrement());
equipment.setProfileId(profileId);
return equipmentDatastore.create(equipment);
}
}

View File

@@ -69,15 +69,15 @@ public class PortalUserDAO extends BaseJdbcDao {
private static final Set<String> columnsToSkipForInsert = new HashSet<>(Arrays.asList(COL_ID));
private static final Set<String> columnsToSkipForUpdate = new HashSet<>(Arrays.asList(COL_ID, "createdTimestamp"));
private static final String TABLE_NAME = "portal_user";
private static final String TABLE_PREFIX = "s.";
private static final String ALL_COLUMNS;
public static final String TABLE_NAME = "portal_user";
public static final String TABLE_PREFIX = "s.";
public static final String ALL_COLUMNS;
private static final Set<String> ALL_COLUMNS_LOWERCASE = new HashSet<>();
public static final Set<String> ALL_COLUMNS_LOWERCASE = new HashSet<>();
@SuppressWarnings("unused")
//use this for queries where multiple tables are involved
private static final String ALL_COLUMNS_WITH_PREFIX;
public static final String ALL_COLUMNS_WITH_PREFIX;
private static final String ALL_COLUMNS_FOR_INSERT;
private static final String BIND_VARS_FOR_INSERT;
@@ -162,8 +162,8 @@ public class PortalUserDAO extends BaseJdbcDao {
private static final String SQL_GET_ALL_IN_SET = "select " + ALL_COLUMNS + " from "+TABLE_NAME + " where "+ COL_ID +" in ";
private static final String SQL_PAGING_SUFFIX = " LIMIT ? OFFSET ? ";
private static final String SORT_SUFFIX = "";
public static final String SQL_PAGING_SUFFIX = " LIMIT ? OFFSET ? ";
public static final String SORT_SUFFIX = "";
private static final RowMapper<PortalUser> portalUserRowMapper = new PortalUserRowMapper();

View File

@@ -370,11 +370,9 @@ public class SsidConfiguration extends ProfileDetails implements PushableConfigu
public static enum SecureMode {
open(0L), wpaPSK(1L), wpa2PSK(2L), wpaRadius(3L), wpa2Radius(4L), wpa2OnlyPSK(5L), wpa2OnlyRadius(6L), wep(
7L), wpaEAP(8L), wpa2EAP(
9L), wpa2OnlyEAP(10L), wpa3OnlySAE(11L), wpa3MixedSAE(12L), wpa3OnlyEAP(13L), wpa3MixedEAP(14L),
UNSUPPORTED(-1L);
open(0L), wpaPSK(1L), wpa2PSK(2L), wpaRadius(3L), wpa2Radius(4L), wpa2OnlyPSK(5L), wpa2OnlyRadius(6L), wep(7L),
wpaEAP(8L), wpa2EAP(9L), wpa2OnlyEAP(10L), wpa3OnlySAE(11L), wpa3MixedSAE(12L), wpa3OnlyEAP(13L), wpa3MixedEAP(14L),
wpa3OnlyEAP192(15L), UNSUPPORTED(-1L);
private final long id;
private static final Map<Long, SecureMode> ELEMENTS = new HashMap<>();
@@ -415,7 +413,7 @@ public class SsidConfiguration extends ProfileDetails implements PushableConfigu
}
public static boolean isWPA3_Enterprise_or_Personal(SecureMode mode) {
return mode == wpa3OnlySAE || mode == wpa3OnlyEAP;
return mode == wpa3OnlySAE || mode == wpa3OnlyEAP || mode == wpa3OnlyEAP192;
}
}

View File

@@ -1024,6 +1024,7 @@ components:
- wpa3MixedSAE
- wpa3OnlyEAP
- wpa3MixedEAP
- wpa3OnlyEAP192
RadioBasedSsidConfigurationMap:
properties:

View File

@@ -1,97 +1,111 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.telecominfraproject.wlan</groupId>
<artifactId>tip-wlan-cloud-root-pom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<relativePath>../../wlan-cloud-root</relativePath>
</parent>
<artifactId>provisioning-sp</artifactId>
<name>provisioning-sp</name>
<description>Stream Processors for provisioning events.</description>
<dependencies>
<dependency>
<artifactId>base-stream-consumer</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<artifactId>provisioning-sp</artifactId>
<name>provisioning-sp</name>
<description>Stream Processors for provisioning events.</description>
<dependency>
<artifactId>service-metric-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependencies>
<dependency>
<artifactId>base-stream-consumer</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>system-event-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>service-metric-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>base-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>routing-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-gateway-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>system-event-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>base-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>location-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>routing-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>profile-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>client-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<!-- models used by the application logic of the stream processor -->
<dependency>
<artifactId>equipment-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>profile-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-gateway-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>location-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
</dependencies>
<dependency>
<artifactId>location-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>profile-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>client-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>alarm-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>status-service-interface</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<!-- models used by the application logic of the stream processor -->
<dependency>
<artifactId>equipment-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>profile-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>location-models</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,3 +1,4 @@
package com.telecominfraproject.wlan.streams.provisioning;
import java.util.ArrayList;
@@ -12,18 +13,24 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.telecominfraproject.wlan.alarm.AlarmServiceInterface;
import com.telecominfraproject.wlan.alarm.models.Alarm;
import com.telecominfraproject.wlan.core.model.json.BaseJsonModel;
import com.telecominfraproject.wlan.core.model.pagination.PaginationContext;
import com.telecominfraproject.wlan.core.model.pagination.PaginationResponse;
import com.telecominfraproject.wlan.core.model.pair.PairLongLong;
import com.telecominfraproject.wlan.core.model.streams.QueuedStreamMessage;
import com.telecominfraproject.wlan.equipment.EquipmentServiceInterface;
import com.telecominfraproject.wlan.equipment.models.ApElementConfiguration;
import com.telecominfraproject.wlan.equipment.models.Equipment;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentApImpactingChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentBlinkLEDsEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentCellSizeAttributesChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentChannelsChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentCustomerChangedEvent;
import com.telecominfraproject.wlan.equipment.models.events.EquipmentRemovedEvent;
import com.telecominfraproject.wlan.equipmentgateway.models.CEGWBaseCommand;
import com.telecominfraproject.wlan.equipmentgateway.models.CEGWBlinkRequest;
import com.telecominfraproject.wlan.equipmentgateway.models.CEGWCloseSessionRequest;
import com.telecominfraproject.wlan.equipmentgateway.models.CEGWConfigChangeNotification;
import com.telecominfraproject.wlan.equipmentgateway.models.CEGWNewChannelRequest;
@@ -35,13 +42,16 @@ import com.telecominfraproject.wlan.profile.models.Profile;
import com.telecominfraproject.wlan.profile.models.events.ProfileAddedEvent;
import com.telecominfraproject.wlan.profile.models.events.ProfileChangedEvent;
import com.telecominfraproject.wlan.profile.models.events.ProfileRemovedEvent;
import com.telecominfraproject.wlan.status.StatusServiceInterface;
import com.telecominfraproject.wlan.status.models.Status;
import com.telecominfraproject.wlan.status.models.StatusDataType;
import com.telecominfraproject.wlan.stream.StreamProcessor;
import com.telecominfraproject.wlan.systemevent.models.SystemEvent;
import com.telecominfraproject.wlan.systemevent.models.SystemEventRecord;
/**
* @author dtop
* This stream processor is listening for events related to changes
* @author dtop
* This stream processor is listening for events related to changes
* in Equipment, Location, and Profile objects. If a change is detected,
* it uses Routing service to find affected equipment and delivers
* CEGWConfigChangeNotification command to the equipment, which results
@@ -50,187 +60,225 @@ import com.telecominfraproject.wlan.systemevent.models.SystemEventRecord;
@Component
public class EquipmentConfigPushTrigger extends StreamProcessor {
private static final Logger LOG = LoggerFactory.getLogger(EquipmentConfigPushTrigger.class);
@Value("${tip.wlan.systemEventsTopic:system_events}")
private String systemEventsTopic;
@Autowired
private EquipmentGatewayServiceInterface equipmentGatewayInterface;
@Autowired
private ProfileServiceInterface profileServiceInterface;
@Autowired
private EquipmentServiceInterface equipmentServiceInterface;
private static final Logger LOG = LoggerFactory.getLogger(EquipmentConfigPushTrigger.class);
@Override
protected boolean acceptMessage(QueuedStreamMessage message) {
boolean ret = message.getTopic().equals(systemEventsTopic);
@Value("${tip.wlan.systemEventsTopic:system_events}")
private String systemEventsTopic;
if(ret && ( message.getModel() instanceof SystemEventRecord) ) {
SystemEventRecord ser = (SystemEventRecord) message.getModel();
ret = ret &&
(
ser.getDetails() instanceof EquipmentApImpactingChangedEvent ||
ser.getDetails() instanceof EquipmentChannelsChangedEvent ||
ser.getDetails() instanceof EquipmentCellSizeAttributesChangedEvent ||
ser.getDetails() instanceof EquipmentRemovedEvent ||
ser.getDetails() instanceof ProfileAddedEvent ||
ser.getDetails() instanceof ProfileChangedEvent ||
ser.getDetails() instanceof ProfileRemovedEvent ||
ser.getDetails() instanceof LocationChangedApImpactingEvent
);
} else {
ret = false;
}
LOG.trace("acceptMessage {}", ret);
return ret;
}
@Override
protected void processMessage(QueuedStreamMessage message) {
SystemEventRecord mdl = (SystemEventRecord) message.getModel();
SystemEvent se = mdl.getDetails();
LOG.debug("Processing {}", mdl);
switch ( se.getClass().getSimpleName() ) {
case "EquipmentApImpactingChangedEvent":
process((EquipmentApImpactingChangedEvent) se);
break;
case "EquipmentChannelsChangedEvent":
@Autowired
private EquipmentGatewayServiceInterface equipmentGatewayInterface;
@Autowired
private ProfileServiceInterface profileServiceInterface;
@Autowired
private EquipmentServiceInterface equipmentServiceInterface;
@Autowired
private StatusServiceInterface statusServiceInterface;
@Autowired
private AlarmServiceInterface alarmServiceInterface;
@Override
protected boolean acceptMessage(QueuedStreamMessage message) {
boolean ret = message.getTopic().equals(systemEventsTopic);
if (ret && (message.getModel() instanceof SystemEventRecord)) {
SystemEventRecord ser = (SystemEventRecord) message.getModel();
ret = ret && (ser.getDetails() instanceof EquipmentApImpactingChangedEvent || ser.getDetails() instanceof EquipmentBlinkLEDsEvent
|| ser.getDetails() instanceof EquipmentChannelsChangedEvent || ser.getDetails() instanceof EquipmentCellSizeAttributesChangedEvent
|| ser.getDetails() instanceof EquipmentRemovedEvent || ser.getDetails() instanceof ProfileAddedEvent
|| ser.getDetails() instanceof ProfileChangedEvent || ser.getDetails() instanceof ProfileRemovedEvent
|| ser.getDetails() instanceof LocationChangedApImpactingEvent || ser.getDetails() instanceof EquipmentCustomerChangedEvent);
} else {
ret = false;
}
LOG.trace("acceptMessage {}", ret);
return ret;
}
@Override
protected void processMessage(QueuedStreamMessage message) {
SystemEventRecord mdl = (SystemEventRecord) message.getModel();
SystemEvent se = mdl.getDetails();
LOG.debug("Processing {}", mdl);
switch (se.getClass().getSimpleName()) {
case "EquipmentApImpactingChangedEvent":
process((EquipmentApImpactingChangedEvent) se);
break;
case "EquipmentChannelsChangedEvent":
process((EquipmentChannelsChangedEvent) se);
break;
case "EquipmentCellSizeAttributesChangedEvent":
case "EquipmentCellSizeAttributesChangedEvent":
process((EquipmentCellSizeAttributesChangedEvent) se);
break;
case "EquipmentRemovedEvent":
case "EquipmentBlinkLEDsEvent":
process((EquipmentBlinkLEDsEvent) se);
break;
case "EquipmentRemovedEvent":
process((EquipmentRemovedEvent) se);
break;
case "ProfileAddedEvent":
process((ProfileAddedEvent) se);
break;
case "ProfileChangedEvent":
process((ProfileChangedEvent) se);
break;
case "ProfileRemovedEvent":
process((ProfileRemovedEvent) se);
break;
case "LocationChangedApImpactingEvent":
process((LocationChangedApImpactingEvent) se);
break;
default:
process(mdl);
}
}
private void process(EquipmentApImpactingChangedEvent model) {
LOG.debug("Processing EquipmentChangedEvent");
equipmentGatewayInterface.sendCommand(new CEGWConfigChangeNotification(model.getPayload().getInventoryId(),
model.getEquipmentId()));
case "ProfileAddedEvent":
process((ProfileAddedEvent) se);
break;
case "ProfileChangedEvent":
process((ProfileChangedEvent) se);
break;
case "ProfileRemovedEvent":
process((ProfileRemovedEvent) se);
break;
case "LocationChangedApImpactingEvent":
process((LocationChangedApImpactingEvent) se);
break;
case "EquipmentCustomerChangedEvent":
process((EquipmentCustomerChangedEvent) se);
default:
process(mdl);
}
}
private void process(EquipmentApImpactingChangedEvent model) {
LOG.debug("Processing EquipmentChangedEvent");
equipmentGatewayInterface.sendCommand(new CEGWConfigChangeNotification(model.getPayload().getInventoryId(), model.getEquipmentId()));
}
private void process(EquipmentChannelsChangedEvent model) {
LOG.debug("Processing EquipmentChannelsChangedEvent for equipmentId {}", model.getEquipmentId());
equipmentGatewayInterface.sendCommand(new CEGWNewChannelRequest(model.getPayload().getInventoryId(), model.getEquipmentId(),
model.getNewBackupChannels(), model.getNewPrimaryChannels()));
}
private void process(EquipmentCellSizeAttributesChangedEvent model) {
LOG.debug("Processing EquipmentCellSizeAttributesChangedEvent for equipmentId {}", model.getEquipmentId());
equipmentGatewayInterface
.sendCommand(new CEGWCellSizeAttributesRequest(model.getPayload().getInventoryId(), model.getEquipmentId(), model.getCellSizeAttributesMap()));
}
private void process(EquipmentBlinkLEDsEvent model) {
LOG.debug("Processing EquipmentBlinkLEDsEvent for equipmentId {}", model.getEquipmentId());
CEGWBlinkRequest br = new CEGWBlinkRequest(model.getPayload().getInventoryId(), model.getEquipmentId());
br.setBlinkAllLEDs(((ApElementConfiguration) model.getPayload().getDetails()).isBlinkAllLEDs());
equipmentGatewayInterface.sendCommand(br);
}
private void process(EquipmentRemovedEvent model) {
LOG.debug("Processing EquipmentRemovedEvent");
equipmentGatewayInterface.sendCommand(new CEGWCloseSessionRequest(model.getPayload().getInventoryId(), model.getEquipmentId()));
}
private void process(ProfileAddedEvent model) {
LOG.debug("Processing ProfileAddedEvent {}", model.getPayload().getId());
processProfile(model.getPayload());
}
private void process(ProfileChangedEvent model) {
LOG.debug("Processing ProfileChangedEvent {}", model.getPayload().getId());
processProfile(model.getPayload());
}
private void process(ProfileRemovedEvent model) {
LOG.debug("Processing ProfileRemovedEvent {}", model.getPayload().getId());
processProfile(model.getPayload());
}
private void processProfile(Profile profile) {
List<PairLongLong> ret = profileServiceInterface.getTopLevelProfiles(new HashSet<>(Arrays.asList(profile.getId())));
if (ret == null || ret.isEmpty()) {
// nothing to do here
return;
}
Set<Long> parentProfileIds = new HashSet<>();
ret.forEach(p -> parentProfileIds.add(p.getValue2()));
// go through all equipmentIds that refer to parent profiles and trigger change config notification on them
PaginationContext<PairLongLong> context = new PaginationContext<>(100);
while (!context.isLastPage()) {
PaginationResponse<PairLongLong> page = equipmentServiceInterface.getEquipmentIdsByProfileIds(parentProfileIds, context);
context = page.getContext();
Set<Long> equipmentIds = new HashSet<>();
page.getItems().forEach(p -> equipmentIds.add(p.getValue2()));
// retrieve full equipment objects to get the inventory id
List<Equipment> equipmentForPage = equipmentServiceInterface.get(equipmentIds);
List<CEGWBaseCommand> commands = new ArrayList<>(equipmentForPage.size());
equipmentForPage.forEach(eq -> commands.add(new CEGWConfigChangeNotification(eq.getInventoryId(), eq.getId())));
equipmentGatewayInterface.sendCommands(commands);
LOG.debug("Page {} - sent {} commands to equipment gateway", context.getLastReturnedPageNumber(), commands.size());
}
LOG.debug("Finished processing profile {}", profile.getId());
}
private void process(LocationChangedApImpactingEvent model) {
LOG.debug("Processing LocationChangedApImpactingEvent {}", model.getPayload().getId());
Set<Long> locationIds = new HashSet<>(Arrays.asList(model.getPayload().getId()));
// go through all equipmentIds that reside in the specified location and trigger change config notification on
// them
PaginationContext<PairLongLong> context = new PaginationContext<>(100);
while (!context.isLastPage()) {
PaginationResponse<PairLongLong> page = equipmentServiceInterface.getEquipmentIdsByLocationIds(locationIds, context);
context = page.getContext();
Set<Long> equipmentIds = new HashSet<>();
page.getItems().forEach(p -> equipmentIds.add(p.getValue2()));
// retrieve full equipment objects to get the inventory id
List<Equipment> equipmentForPage = equipmentServiceInterface.get(equipmentIds);
List<CEGWBaseCommand> commands = new ArrayList<>(equipmentForPage.size());
equipmentForPage.forEach(eq -> commands.add(new CEGWConfigChangeNotification(eq.getInventoryId(), eq.getId())));
equipmentGatewayInterface.sendCommands(commands);
LOG.debug("Page {} - sent {} commands to equipment gateway", context.getLastReturnedPageNumber(), commands.size());
}
LOG.debug("Finished processing LocationChangedApImpactingEvent {}", model.getPayload().getId());
}
private void process(EquipmentCustomerChangedEvent model) {
LOG.info("Processing EquipmentCustomerChangedEvent {}", model.getPayload().getId());
private void process(EquipmentChannelsChangedEvent model) {
LOG.debug("Processing EquipmentChannelsChangedEvent for equipmentId {}", model.getEquipmentId());
equipmentGatewayInterface.sendCommand(new CEGWNewChannelRequest(model.getPayload().getInventoryId(),
model.getEquipmentId(), model.getNewBackupChannels(), model.getNewPrimaryChannels()));
Equipment existingEquipment = model.getExistingEquipment();
Equipment equipment = model.getEquipment();
// when customerId changes, we keep the EQUIPMENT_ADMIN and PROTOCOL status of the AP
Status status = statusServiceInterface.getOrNull(existingEquipment.getCustomerId(), existingEquipment.getId(), StatusDataType.EQUIPMENT_ADMIN);
if (status != null) {
status.setCustomerId(equipment.getCustomerId());
statusServiceInterface.update(status);
}
private void process(EquipmentCellSizeAttributesChangedEvent model) {
LOG.debug("Processing EquipmentCellSizeAttributesChangedEvent for equipmentId {}", model.getEquipmentId());
equipmentGatewayInterface.sendCommand(new CEGWCellSizeAttributesRequest(model.getPayload().getInventoryId(),
model.getEquipmentId(), model.getCellSizeAttributesMap()));
status = statusServiceInterface.getOrNull(existingEquipment.getCustomerId(), existingEquipment.getId(), StatusDataType.PROTOCOL);
if (status != null) {
status.setCustomerId(equipment.getCustomerId());
statusServiceInterface.update(status);
}
private void process(EquipmentRemovedEvent model) {
LOG.debug("Processing EquipmentRemovedEvent");
equipmentGatewayInterface.sendCommand(new CEGWCloseSessionRequest(model.getPayload().getInventoryId(), model.getEquipmentId()));
// Alarms has to move to new customerId as well
List<Alarm> oldCustomerAlarms = alarmServiceInterface.get(existingEquipment.getCustomerId(), Set.of(existingEquipment.getId()), null);
if (!oldCustomerAlarms.isEmpty()) {
oldCustomerAlarms.stream().forEach(a -> {
a.setCustomerId(equipment.getCustomerId());
Alarm alarm = alarmServiceInterface.create(a);
LOG.debug("Move an alarm to new customer {}", alarm);
});
}
private void process(ProfileAddedEvent model) {
LOG.debug("Processing ProfileAddedEvent {}", model.getPayload().getId());
processProfile(model.getPayload());
}
alarmServiceInterface.delete(existingEquipment.getCustomerId(), existingEquipment.getId());
}
private void process(ProfileChangedEvent model) {
LOG.debug("Processing ProfileChangedEvent {}", model.getPayload().getId());
processProfile(model.getPayload());
}
private void process(BaseJsonModel model) {
LOG.warn("Unprocessed model: {}", model);
}
private void process(ProfileRemovedEvent model) {
LOG.debug("Processing ProfileRemovedEvent {}", model.getPayload().getId());
processProfile(model.getPayload());
}
private void processProfile(Profile profile) {
List<PairLongLong> ret = profileServiceInterface.getTopLevelProfiles(new HashSet<>(Arrays.asList(profile.getId())));
if(ret == null || ret.isEmpty()) {
//nothing to do here
return;
}
Set<Long> parentProfileIds = new HashSet<>();
ret.forEach(p -> parentProfileIds.add(p.getValue2()));
//go through all equipmentIds that refer to parent profiles and trigger change config notification on them
PaginationContext<PairLongLong> context = new PaginationContext<>(100);
while(!context.isLastPage()) {
PaginationResponse<PairLongLong> page = equipmentServiceInterface.getEquipmentIdsByProfileIds(parentProfileIds, context );
context = page.getContext();
Set<Long> equipmentIds = new HashSet<>();
page.getItems().forEach(p -> equipmentIds.add(p.getValue2()));
//retrieve full equipment objects to get the inventory id
List<Equipment> equipmentForPage = equipmentServiceInterface.get(equipmentIds);
List<CEGWBaseCommand> commands = new ArrayList<>(equipmentForPage.size());
equipmentForPage.forEach(eq -> commands.add(new CEGWConfigChangeNotification(eq.getInventoryId(), eq.getId())));
equipmentGatewayInterface.sendCommands(commands);
LOG.debug("Page {} - sent {} commands to equipment gateway", context.getLastReturnedPageNumber(), commands.size());
}
LOG.debug("Finished processing profile {}", profile.getId());
}
private void process(LocationChangedApImpactingEvent model) {
LOG.debug("Processing LocationChangedApImpactingEvent {}", model.getPayload().getId());
Set<Long> locationIds = new HashSet<>(Arrays.asList(model.getPayload().getId()));
//go through all equipmentIds that reside in the specified location and trigger change config notification on them
PaginationContext<PairLongLong> context = new PaginationContext<>(100);
while(!context.isLastPage()) {
PaginationResponse<PairLongLong> page = equipmentServiceInterface.getEquipmentIdsByLocationIds(locationIds, context );
context = page.getContext();
Set<Long> equipmentIds = new HashSet<>();
page.getItems().forEach(p -> equipmentIds.add(p.getValue2()));
//retrieve full equipment objects to get the inventory id
List<Equipment> equipmentForPage = equipmentServiceInterface.get(equipmentIds);
List<CEGWBaseCommand> commands = new ArrayList<>(equipmentForPage.size());
equipmentForPage.forEach(eq -> commands.add(new CEGWConfigChangeNotification(eq.getInventoryId(), eq.getId())));
equipmentGatewayInterface.sendCommands(commands);
LOG.debug("Page {} - sent {} commands to equipment gateway", context.getLastReturnedPageNumber(), commands.size());
}
LOG.debug("Finished processing LocationChangedApImpactingEvent {}", model.getPayload().getId());
}
private void process(BaseJsonModel model) {
LOG.warn("Unprocessed model: {}", model);
}
}

View File

@@ -53,12 +53,6 @@
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>equipment-alarms-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>
<version>1.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>adoption-metrics-sp</artifactId>
<groupId>com.telecominfraproject.wlan</groupId>

View File

@@ -1,7 +1,9 @@
package com.telecominfraproject.wlan.status.equipment.models;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import com.telecominfraproject.wlan.status.models.StatusCode;
import com.telecominfraproject.wlan.status.models.StatusDataType;
@@ -29,70 +31,29 @@ public class EquipmentAdminStatusData extends StatusDetails {
*/
private String statusMessage;
private Map<String, Long> alarmTimestamps;
private LedStatus ledStatus;
private Map<String,Long> alarmTimestamps;
public EquipmentAdminStatusData() {
}
@Override
public StatusDataType getStatusDataType() {
return StatusDataType.EQUIPMENT_ADMIN;
return StatusDataType.EQUIPMENT_ADMIN;
}
public EquipmentAdminStatusData(EquipmentAdminStatusData data) {
this.statusCode = data.statusCode;
this.statusMessage = data.statusMessage;
this.alarmTimestamps = data.alarmTimestamps==null?null:new HashMap<>(data.alarmTimestamps);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((alarmTimestamps == null) ? 0 : alarmTimestamps.hashCode());
result = prime * result + ((statusCode == null) ? 0 : statusCode.hashCode());
result = prime * result + ((statusMessage == null) ? 0 : statusMessage.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof EquipmentAdminStatusData)) {
return false;
}
EquipmentAdminStatusData other = (EquipmentAdminStatusData) obj;
if (alarmTimestamps == null) {
if (other.alarmTimestamps != null) {
return false;
}
} else if (!alarmTimestamps.equals(other.alarmTimestamps)) {
return false;
}
if (statusCode != other.statusCode) {
return false;
}
if (statusMessage == null) {
if (other.statusMessage != null) {
return false;
}
} else if (!statusMessage.equals(other.statusMessage)) {
return false;
}
return true;
this.alarmTimestamps = data.alarmTimestamps == null ? null : new HashMap<>(data.alarmTimestamps);
}
@Override
public EquipmentAdminStatusData clone() {
EquipmentAdminStatusData res = (EquipmentAdminStatusData) super.clone();
if(this.alarmTimestamps != null) {
if (this.alarmTimestamps != null) {
res.setAlarmTimestamps(new HashMap<>(this.alarmTimestamps));
}
return res;
@@ -121,26 +82,54 @@ public class EquipmentAdminStatusData extends StatusDetails {
public void setAlarmTimestamps(Map<String, Long> alarmTimestamps) {
this.alarmTimestamps = alarmTimestamps;
}
public long findAlarmTimeOrZero(String alarmKey) {
return alarmTimestamps==null?0:alarmTimestamps.getOrDefault(alarmKey, 0l);
return alarmTimestamps == null ? 0 : alarmTimestamps.getOrDefault(alarmKey, 0l);
}
public void putAlarmTimestamp(String alarmKey, long value) {
if(alarmTimestamps == null) {
if (alarmTimestamps == null) {
alarmTimestamps = new HashMap<>();
}
alarmTimestamps.put(alarmKey, value);
}
@Override
public boolean hasUnsupportedValue() {
if (super.hasUnsupportedValue()) {
return true;
}
if (StatusCode.isUnsupported(statusCode) ) {
if (StatusCode.isUnsupported(statusCode)) {
return true;
}
return false;
}
public LedStatus getLedStatus() {
return ledStatus;
}
public void setLedStatus(LedStatus ledStatus) {
this.ledStatus = ledStatus;
}
@Override
public int hashCode() {
return Objects.hash(alarmTimestamps, ledStatus, statusCode, statusMessage);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EquipmentAdminStatusData other = (EquipmentAdminStatusData) obj;
return Objects.equals(alarmTimestamps, other.alarmTimestamps) && ledStatus == other.ledStatus && statusCode == other.statusCode
&& Objects.equals(statusMessage, other.statusMessage);
}
}

View File

@@ -12,6 +12,7 @@ public class EquipmentChannelStatusData extends StatusDetails {
private static final long serialVersionUID = 470569467119609438L;
private Map<RadioType, Integer> channelNumberStatusDataMap = new EnumMap<>(RadioType.class);
private Map<RadioType, Integer> txPowerDataMap = new EnumMap<>(RadioType.class);
public EquipmentChannelStatusData()
@@ -34,10 +35,18 @@ public class EquipmentChannelStatusData extends StatusDetails {
public Map<RadioType, Integer> getChannelNumberStatusDataMap() {
return channelNumberStatusDataMap;
}
public Map<RadioType, Integer> getTxPowerDataMap() {
return txPowerDataMap;
}
public void setChannelNumberStatusDataMap(Map<RadioType, Integer> channelNumberStatusDataMap) {
this.channelNumberStatusDataMap = channelNumberStatusDataMap;
}
public void setTxPowerDataMap(Map<RadioType, Integer> txPowerDataMap) {
this.txPowerDataMap = txPowerDataMap;
}
@Override
public EquipmentChannelStatusData clone() {
@@ -49,19 +58,33 @@ public class EquipmentChannelStatusData extends StatusDetails {
result.channelNumberStatusDataMap.put(k, v);
});
}
if (getTxPowerDataMap() != null) {
result.setTxPowerDataMap(new EnumMap<>(RadioType.class));
this.txPowerDataMap.forEach((k, v) -> {
result.txPowerDataMap.put(k, v);
});
}
return result;
}
@Override
public boolean equals(Object obj) {
EquipmentChannelStatusData other = (EquipmentChannelStatusData) obj;
return Objects.equals(channelNumberStatusDataMap, other.channelNumberStatusDataMap);
public int hashCode() {
return Objects.hash(channelNumberStatusDataMap, txPowerDataMap);
}
@Override
public int hashCode() {
return Objects.hash(channelNumberStatusDataMap);
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EquipmentChannelStatusData other = (EquipmentChannelStatusData) obj;
return Objects.equals(channelNumberStatusDataMap, other.channelNumberStatusDataMap)
&& Objects.equals(txPowerDataMap, other.txPowerDataMap);
}
}

View File

@@ -0,0 +1,6 @@
package com.telecominfraproject.wlan.status.equipment.models;
public enum LedStatus {
led_blink, led_off, UNKNOWN,
}

View File

@@ -197,6 +197,15 @@ components:
$ref: '#/components/schemas/StatusCode'
statusMessage:
type: string
ledStatus:
$ref: '#/components/schemas/LedStatus'
LedStatus:
type: string
enum:
- led_blink
- led_off
- UNKNOWN
StatusCode:
type: string

View File

@@ -3172,6 +3172,14 @@ components:
- wpa2OnlyPSK
- wpa2OnlyRadius
- wep
- wpaEAP
- wpa2EAP
- wpa2OnlyEAP
- wpa3OnlySAE
- wpa3MixedSAE
- wpa3OnlyEAP
- wpa3MixedEAP
- wpa3OnlyEAP192
RadioBasedSsidConfigurationMap:
properties:
@@ -3466,6 +3474,15 @@ components:
$ref: '#/components/schemas/StatusCode'
statusMessage:
type: string
ledStatus:
$ref: '#/components/schemas/LedStatus'
LedStatus:
type: string
enum:
- led_blink
- led_off
- UNKNOWN
StatusCode:
type: string
@@ -4401,6 +4418,8 @@ components:
- RADIO_CHANNEL
channelNumberStatusDataMap:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
txPowerDataMap:
$ref: '#/components/schemas/IntegerPerRadioTypeMap'
#
# Equipment configuration data models
@@ -4510,6 +4529,8 @@ components:
type: boolean
forwardMode:
$ref: '#/components/schemas/NetworkForwardMode'
blinkAllLEDs:
type: boolean
radioMap:
$ref: '#/components/schemas/RadioMap'
advancedRadioMap: