Added support for PM filtering of the MO class of the measured object.
Changed the ICS producer ID so that each instance will have a unique ID (using the callback URL).
Changed the Kafka group ID so that each type will have an own group ID
Setting kafka client ID (using the callback URL)
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
Issue-ID: NONRTRIC-773
Change-Id: I1031802469beb146039ed089e4c80f0ca83d4dd9
For instance a value like "NRCellCU" will match "ManagedElement=seliitdus00487,GNBCUCPFunction=1,NRCellCU=32".
* measTypes selects the meas types to get
* measuredEntityDns partial match of meas entity DNs.
+* measObjClass matching of the class of the measObjInstId. The measObjInstId must follow the 3GPP naming conventions for Managed Objects (3GPP TS 32.106-8).
+ Example, for a distinguished name "ManagedElement=RNC-Gbg-1,ENodeBFunction=1", the MO class will be "ENodeBFunction".
All PM filter properties are optional and a non given will result in "match all".
The result of the filtering is still following the structure of a 3GPP PM report.
.. code-block:: javascript
{
- "filterType":"pmdata"
+ "filterType":"pmdata",
"filter": {
"sourceNames":[
"O-DU-1122"
],
"measTypes":[
"succImmediateAssignProcs"
- ],eparate call.
+ ],
"measuredEntityDns":[
"ManagedElement=RNC-Gbg-1"
]
public class ErrorResponse {
private static Gson gson = new GsonBuilder() //
+ .disableHtmlEscaping() //
.create(); //
// Returned as body for all failed REST calls
public static final String API_DESCRIPTION = "";
public static final String JOB_URL = "/generic_dataproducer/info_job";
public static final String SUPERVISION_URL = "/generic_dataproducer/health_check";
- private static Gson gson = new GsonBuilder().create();
+ private static Gson gson = new GsonBuilder().disableHtmlEscaping().create();
private final Jobs jobs;
private final InfoTypes types;
@ToString
public class Job {
- private static com.google.gson.Gson gson = new GsonBuilder().create();
+ private static com.google.gson.Gson gson = new GsonBuilder().disableHtmlEscaping().create();
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static class Parameters {
private String expression;
private static final Logger logger = LoggerFactory.getLogger(JsonPathFilter.class);
- com.google.gson.Gson gson = new com.google.gson.GsonBuilder().create();
+ com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
public JsonPathFilter(String exp) {
try {
public class PmReportFilter implements Filter {
- private static com.google.gson.Gson gson = new com.google.gson.GsonBuilder().create();
+ private static com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
private final FilterData filterData;
@Getter
final Collection<String> measObjInstIds = new ArrayList<>();
final Collection<String> measTypes = new HashSet<>();
final Collection<String> measuredEntityDns = new ArrayList<>();
+ final Collection<String> measObjClass = new HashSet<>();
}
private static class MeasTypesIndexed extends PmReport.MeasTypes {
return newMeasResults;
}
+ private boolean isMeasInstIdMatch(String measObjInstId, FilterData filter) {
+ return filter.measObjInstIds.isEmpty() || isContainedInAny(measObjInstId, filter.measObjInstIds);
+ }
+
+ private String managedObjectClass(String distinguishedName) {
+ int lastRdn = distinguishedName.lastIndexOf(",");
+ if (lastRdn == -1) {
+ return "";
+ }
+ int lastEqualChar = distinguishedName.indexOf("=", lastRdn);
+ if (lastEqualChar == -1) {
+ return "";
+ }
+ return distinguishedName.substring(lastRdn + 1, lastEqualChar);
+ }
+
+ private boolean isMeasInstClassMatch(String measObjInstId, FilterData filter) {
+ if (filter.measObjClass.isEmpty()) {
+ return true;
+ }
+
+ String measObjClass = managedObjectClass(measObjInstId);
+ return filter.measObjClass.contains(measObjClass);
+ }
+
private PmReport.MeasValuesList createMeasValuesList(PmReport.MeasValuesList oldMeasValues,
PmReport.MeasTypes measTypes, FilterData filter) {
PmReport.MeasValuesList newMeasValuesList = oldMeasValues.shallowClone();
- if (filter.measObjInstIds.isEmpty() || isContainedInAny(oldMeasValues.measObjInstId, filter.measObjInstIds)) {
+ if (isMeasInstIdMatch(oldMeasValues.measObjInstId, filter)
+ && isMeasInstClassMatch(oldMeasValues.measObjInstId, filter)) {
newMeasValuesList.measResults = createMeasResults(oldMeasValues.measResults, measTypes, filter);
}
return newMeasValuesList;
private final AsyncRestClient dmaapRestClient;
private final ApplicationConfig applicationConfig;
private final InfoType type;
- private final com.google.gson.Gson gson = new com.google.gson.GsonBuilder().create();
+ private final com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
private Flux<DataFromTopic> dataFromDmaap;
public DmaapTopicListener(ApplicationConfig applicationConfig, InfoType type, SecurityContext securityContext) {
logger.error("No kafka boostrap server is setup");
}
consumerProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, this.applicationConfig.getKafkaBootStrapServers());
- consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG, "osc-dmaap-adapter");
+ consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG, "osc-dmaap-adapter-" + this.type.getId());
consumerProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
consumerProps.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
+ consumerProps.put(ConsumerConfig.CLIENT_ID_CONFIG, this.applicationConfig.getSelfUrl());
return ReceiverOptions.<String, String>create(consumerProps)
.subscription(Collections.singleton(this.type.getKafkaInputTopic()));
private final AsyncRestClient restClient;
private final ApplicationConfig applicationConfig;
private final InfoTypes types;
- private static com.google.gson.Gson gson = new com.google.gson.GsonBuilder().create();
+ private static com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
- private static final String PRODUCER_ID = "DmaapGenericInfoProducer";
@Getter
private boolean isRegisteredInIcs = false;
private static final int REGISTRATION_SUPERVISION_INTERVAL_MS = 1000 * 10;
logger.warn("Registration of producer failed {}", t.getMessage());
}
+ private String producerRegistrationUrl() {
+ final String producerId = this.applicationConfig.getSelfUrl().replace("/", "_");
+ return applicationConfig.getIcsBaseUrl() + "/data-producer/v1/info-producers/" + producerId;
+ }
+
// Returns TRUE if registration is correct
private Mono<Boolean> checkRegistration() {
- final String url = applicationConfig.getIcsBaseUrl() + "/data-producer/v1/info-producers/" + PRODUCER_ID;
- return restClient.get(url) //
+ return restClient.get(producerRegistrationUrl()) //
.flatMap(this::isRegisterredInfoCorrect) //
.onErrorResume(t -> Mono.just(Boolean.FALSE));
}
private Mono<String> registerTypesAndProducer() {
final int CONCURRENCY = 20;
- final String producerUrl =
- applicationConfig.getIcsBaseUrl() + "/data-producer/v1/info-producers/" + PRODUCER_ID;
return Flux.fromIterable(this.types.getAll()) //
.doOnNext(type -> logger.info("Registering type {}", type.getId())) //
CONCURRENCY) //
.collectList() //
.doOnNext(type -> logger.info("Registering producer")) //
- .flatMap(resp -> restClient.put(producerUrl, gson.toJson(producerRegistrationInfo())));
+ .flatMap(resp -> restClient.put(producerRegistrationUrl(), gson.toJson(producerRegistrationInfo())));
}
private Object typeSpecifcInfoObject() {
}
]
},
+ "measObjClass": {
+ "type": "array",
+ "items": [
+ {
+ "type": "string"
+ }
+ ]
+ },
"measTypes": {
"type": "array",
"items": [
public class IcsSimulatorController {
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private final static Gson gson = new GsonBuilder().create();
+ private final static Gson gson = new GsonBuilder().disableHtmlEscaping().create();
public static class TestResults {
@Autowired
private SecurityContext securityContext;
- private static Gson gson = new GsonBuilder().create();
+ private static Gson gson = new GsonBuilder().disableHtmlEscaping().create();
static class TestApplicationConfig extends ApplicationConfig {
@Autowired
private SecurityContext securityContext;
- private static com.google.gson.Gson gson = new com.google.gson.GsonBuilder().create();
+ private static com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
private final Logger logger = LoggerFactory.getLogger(IntegrationWithKafka.class);
@SuppressWarnings("squid:S2925") // "Thread.sleep" should not be used in tests.
@Test
void kafkaCharacteristics_pmFilter() throws Exception {
- // Filter PM reports and senttotowjobs over Kafka
+ // Filter PM reports and sent to two jobs over Kafka
final String JOB_ID = "kafkaCharacteristics";
final String JOB_ID2 = "kafkaCharacteristics2";
PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
filterData.getMeasTypes().add("succImmediateAssignProcs");
- filterData.getMeasObjInstIds().add("UtranCell");
+ filterData.getMeasObjClass().add("UtranCell");
this.icsSimulatorController.addJob(consumerJobInfoKafka(kafkaReceiver.OUTPUT_TOPIC, filterData), JOB_ID,
restClient());
assertThat(filtered).contains("Gbg-997").doesNotContain("Gbg-998");
}
+ @Test
+ void testMeasObjClass() throws Exception {
+ PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
+ filterData.measObjClass.add("junk");
+ PmReportFilter filter = new PmReportFilter(filterData);
+ String filtered = filter.filter(loadReport());
+ assertThat(filtered).isEmpty();
+
+ filterData = new PmReportFilter.FilterData();
+ filterData.measObjClass.add("ENodeBFunction");
+ filter = new PmReportFilter(filterData);
+ filtered = filter.filter(loadReport());
+ assertThat(filtered).contains("ENodeBFunction").doesNotContain("UtranCell");
+ }
+
@Test
void testSourceNames() throws Exception {
PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
@Test
void testParse() throws Exception {
- com.google.gson.Gson gson = new com.google.gson.GsonBuilder().create();
+ com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
PmReport report = gson.fromJson(loadReport(), PmReport.class);
String dn = report.event.perf3gppFields.measDataCollection.measuredEntityDn;