From 4a8c2cb9920983f8b8af75be90f7511a59e923f5 Mon Sep 17 00:00:00 2001 From: Serban Popescu Date: Mon, 26 Mar 2018 13:36:17 +0000 Subject: Add Aai event listener Add support for Aai and Pserver incoming messages from Dmaap Change-Id: I57fedcaf6668d09189f0246571e8aaf515fc3fa0 Issue-ID: CCSDK-223 Signed-off-by: Serban Popescu --- dmaap-listener/pom.xml | 6 + dmaap-listener/src/assembly/assemble_zip.xml | 1 + .../dmaapclient/SdncAaiDmaapConsumer.java | 205 +++++++++++++++++++++ dmaap-listener/src/main/resources/pserver.map | 5 + .../src/main/resources/template-pserver.vt | 11 ++ .../dmaapclient/TestSdncPserverDmaapReceiver.java | 85 +++++++++ .../resources/dmaap-consumer-pserver.properties | 34 ++++ 7 files changed, 347 insertions(+) create mode 100644 dmaap-listener/src/main/java/org/onap/ccsdk/sli/northbound/dmaapclient/SdncAaiDmaapConsumer.java create mode 100644 dmaap-listener/src/main/resources/pserver.map create mode 100644 dmaap-listener/src/main/resources/template-pserver.vt create mode 100644 dmaap-listener/src/test/java/org/onap/ccsdk/sli/northbound/dmaapclient/TestSdncPserverDmaapReceiver.java create mode 100644 dmaap-listener/src/test/resources/dmaap-consumer-pserver.properties diff --git a/dmaap-listener/pom.xml b/dmaap-listener/pom.xml index f6d04e24..3a75fef0 100755 --- a/dmaap-listener/pom.xml +++ b/dmaap-listener/pom.xml @@ -20,6 +20,7 @@ 1.2.0-SNAPSHOT 2.9.0.pr1 + 1.7 true /opt/app/dmaap-listener 1.1.0-SNAPSHOT @@ -67,6 +68,11 @@ jackson-annotations ${fasterxml.jackson.version} + + org.apache.velocity + velocity + ${velocity.version} + junit junit diff --git a/dmaap-listener/src/assembly/assemble_zip.xml b/dmaap-listener/src/assembly/assemble_zip.xml index f8873ab4..632172d7 100644 --- a/dmaap-listener/src/assembly/assemble_zip.xml +++ b/dmaap-listener/src/assembly/assemble_zip.xml @@ -48,6 +48,7 @@ *.properties *.map + *.vt diff --git a/dmaap-listener/src/main/java/org/onap/ccsdk/sli/northbound/dmaapclient/SdncAaiDmaapConsumer.java b/dmaap-listener/src/main/java/org/onap/ccsdk/sli/northbound/dmaapclient/SdncAaiDmaapConsumer.java new file mode 100644 index 00000000..4b695fce --- /dev/null +++ b/dmaap-listener/src/main/java/org/onap/ccsdk/sli/northbound/dmaapclient/SdncAaiDmaapConsumer.java @@ -0,0 +1,205 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.northbound.dmaapclient; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SdncAaiDmaapConsumer extends SdncDmaapConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(SdncAaiDmaapConsumer.class); + private static final String SDNC_ENDPOINT = "SDNC.endpoint"; + private static final String TEMPLATE = "SDNC.template"; + private static final String DMAAPLISTENERROOT = "DMAAPLISTENERROOT"; + + private static final String AAI_EVENT = "AAI-EVENT"; + + private static final String EVENT_TYPE = "event-type"; + private static final String ENTITY_TYPE = "entity-type"; + private static final String EVENT_HEADER = "event-header"; + + private String rootDir; + + protected VelocityEngine velocityEngine; + + public SdncAaiDmaapConsumer() { + velocityEngine = new VelocityEngine(); + Properties props = new Properties(); + rootDir = System.getenv(DMAAPLISTENERROOT); + + if ((rootDir == null) || (rootDir.length() == 0)) { + rootDir = "/opt/app/dmaap-listener/lib/"; + } + else { + rootDir = rootDir + "/lib/"; + } + + props.put("file.resource.loader.path", rootDir); + velocityEngine.init(props); + } + + /* + * for testing purposes + */ + SdncAaiDmaapConsumer(Properties props) { + velocityEngine = new VelocityEngine(); + velocityEngine.init(props); + } + + protected String publish(String templatePath, String jsonString) throws IOException + { + JSONObject jsonObj = new JSONObject(jsonString); + VelocityContext context = new VelocityContext(); + for(Object key : jsonObj.keySet()) + { + context.put((String)key, jsonObj.get((String)key)); + } + + context.put("curr_time", Instant.now()); + + ObjectMapper oMapper = new ObjectMapper(); + + String rpcMsgbody = oMapper.writeValueAsString(jsonString); + context.put("full_message", rpcMsgbody); + + Writer writer = new StringWriter(); + velocityEngine.mergeTemplate(templatePath, "UTF-8", context, writer); + writer.flush(); + + return writer.toString(); + } + + @Override + public void processMsg(String msg) throws InvalidMessageException { + + if (msg == null) { + throw new InvalidMessageException("Null message"); + } + + ObjectMapper oMapper = new ObjectMapper(); + JsonNode aaiRootNode; + try { + aaiRootNode = oMapper.readTree(msg); + } catch (Exception e) { + throw new InvalidMessageException("Cannot parse json object", e); + } + + JsonNode eventHeaderNode = aaiRootNode.get(EVENT_HEADER); + if(eventHeaderNode == null) { + LOG.info("Missing Event Header node."); + return; + } + JsonNode eventTypeNode = eventHeaderNode.get(EVENT_TYPE); + String eventType = eventTypeNode.textValue(); + + if(AAI_EVENT.equals(eventType) == false) { + LOG.info("Unknown Event Type {}", eventType); + return; + } + + JsonNode entityTypeNode = eventHeaderNode.get(ENTITY_TYPE); + String entityType = entityTypeNode.textValue(); + + String mapFilename = rootDir + entityType + ".map"; + Map fieldMap = loadMap(mapFilename); + if (fieldMap == null) { + throw new InvalidMessageException("Unable to process message - cannot load mapping file"); + } + + if (!fieldMap.containsKey(SDNC_ENDPOINT)) { + throw new InvalidMessageException("No SDNC endpoint known for message " + entityType); + } + String sdncEndpoint = fieldMap.get(SDNC_ENDPOINT); + + if (!fieldMap.containsKey(TEMPLATE)) { + throw new InvalidMessageException("No SDNC template known for message " + entityType); + } + String templateName = fieldMap.get(TEMPLATE); + + try { + String rpcMsgbody = publish(templateName, msg); + String odlUrlBase = getProperty("sdnc.odl.url-base"); + String odlUser = getProperty("sdnc.odl.user"); + String odlPassword = getProperty("sdnc.odl.password"); + + if ((odlUrlBase != null) && (odlUrlBase.length() > 0)) { + SdncOdlConnection conn = SdncOdlConnection.newInstance(odlUrlBase + sdncEndpoint, odlUser, odlPassword); + + conn.send("POST", "application/json", rpcMsgbody); + } else { + LOG.info("POST message body would be:\n" + rpcMsgbody); + } + } catch (Exception e) { + LOG.error("Unable to process message", e); + } + } + + private Map loadMap(String mapFilename) { + File mapFile = new File(mapFilename); + + if (!mapFile.canRead()) { + LOG.error(String.format("Cannot read map file (%s)", mapFilename)); + return null; + } + + Map results = new HashMap<>(); + try (BufferedReader mapReader = new BufferedReader(new FileReader(mapFile))) { + + String curLine; + + while ((curLine = mapReader.readLine()) != null) { + curLine = curLine.trim(); + + if ((curLine.length() > 0) && (!curLine.startsWith("#")) && curLine.contains("=>")) { + String[] entry = curLine.split("=>"); + if (entry.length == 2) { + results.put(entry[0].trim(), entry[1].trim()); + } + } + } + mapReader.close(); + } catch (Exception e) { + LOG.error("Caught exception reading map " + mapFilename, e); + return null; + } + + return results; + } + +} diff --git a/dmaap-listener/src/main/resources/pserver.map b/dmaap-listener/src/main/resources/pserver.map new file mode 100644 index 00000000..8b3e463e --- /dev/null +++ b/dmaap-listener/src/main/resources/pserver.map @@ -0,0 +1,5 @@ +# SDN-C URL +SDNC.endpoint => config-selfservice-api:notification-callback + +# Field mapping +SDNC.template => template-pserver.vt diff --git a/dmaap-listener/src/main/resources/template-pserver.vt b/dmaap-listener/src/main/resources/template-pserver.vt new file mode 100644 index 00000000..1df659e0 --- /dev/null +++ b/dmaap-listener/src/main/resources/template-pserver.vt @@ -0,0 +1,11 @@ +{ + "input": { + "common-header": { + "request-id": "$event-header.id", + "timestamp": "$curr_time", + "originator-id": "AAI", + "api-ver": "2.00" + }, + "payload": $full_message + } +} \ No newline at end of file diff --git a/dmaap-listener/src/test/java/org/onap/ccsdk/sli/northbound/dmaapclient/TestSdncPserverDmaapReceiver.java b/dmaap-listener/src/test/java/org/onap/ccsdk/sli/northbound/dmaapclient/TestSdncPserverDmaapReceiver.java new file mode 100644 index 00000000..db7cbd72 --- /dev/null +++ b/dmaap-listener/src/test/java/org/onap/ccsdk/sli/northbound/dmaapclient/TestSdncPserverDmaapReceiver.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package org.onap.ccsdk.sli.northbound.dmaapclient; + +import static org.junit.Assert.assertTrue; + +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; + +public class TestSdncPserverDmaapReceiver { + private static final String aaiInput = "{\r\n" + + " \"cambria.partition\": \"AAI\",\r\n" + + " \"event-header\": {\r\n" + + " \"severity\": \"NORMAL\",\r\n" + + " \"entity-type\": \"pserver\",\r\n" + + " \"top-entity-type\": \"pserver\",\r\n" + + " \"entity-link\": \"https://aai.com:8443/aai/v11/cloud-infrastructure/pservers/pserver/a3d3d3d3/\",\r\n" + + " \"event-type\": \"AAI-EVENT\",\r\n" + + " \"domain\": \"e2e\",\r\n" + + " \"action\": \"UPDATE\",\r\n" + + " \"sequence-number\": \"0\",\r\n" + + " \"id\": \"20170415000111-1234\",\r\n" + + " \"source-name\": \"testclient\",\r\n" + + " \"version\": \"v11\",\r\n" + + " \"timestamp\": \"20170415-00:01:11:979\"\r\n" + + " },\r\n" + + " \"entity\": {\r\n" + + " \"hostname\": \"host1\",\r\n" + + " \"ptnii-equip-name\": \"lat111\",\r\n" + + " \"equip-type\": \"server\",\r\n" + + " \"equip-vendor\": \"HP\",\r\n" + + " \"equip-model\": \"model1\",\r\n" + + " \"fqdn\": \"l.global.net\",\r\n" + + " \"ipv4-oam-address\": \"12.12.12.12\",\r\n" + + " \"in-maint\": false,\r\n" + + " \"resource-version\": \"11111111111\",\r\n" + + " \"purpose\": \"Gamma\",\r\n" + + " \"relationship-list\": {\r\n" + + " \"relationship\": [\r\n" + + " {\r\n" + + " \"related-to\": \"complex\",\r\n" + + " \"relationship-data\": [\r\n" + + " {\r\n" + + " \"relationship-value\": \"L1L2L3\",\r\n" + + " \"relationship-key\": \"complex.physical-location-id\"\r\n" + + " }\r\n" + + " ],\r\n" + + " \"related-link\": \"https://aai.com:8443/aai/v11/cloud-infrastructure/complexes/complex/cmpl1\"\r\n" + + " }\r\n" + + " ]\r\n" + + " },\r\n" + + " \"p-interfaces\": {\r\n" + + " \"p-interface\": []\r\n" + + " },\r\n" + + " \"lag-interfaces\": {\r\n" + + " \"lag-interface\": []\r\n" + + " }\r\n" + + " }\r\n" + + "}"; + + @Before + public void setUp() throws Exception { + } + + @Test + public void test() throws Exception { + Properties props = new Properties(); + + String rpcMsgbody = new SdncAaiDmaapConsumer(props).publish("src/main/resources/template-pserver.vt", aaiInput); + + assertTrue(rpcMsgbody.indexOf("input") != -1); + assertTrue(rpcMsgbody.indexOf("payload") != -1); + assertTrue(rpcMsgbody.indexOf("common-header") != -1); + } + + +} diff --git a/dmaap-listener/src/test/resources/dmaap-consumer-pserver.properties b/dmaap-listener/src/test/resources/dmaap-consumer-pserver.properties new file mode 100644 index 00000000..e3c4fdac --- /dev/null +++ b/dmaap-listener/src/test/resources/dmaap-consumer-pserver.properties @@ -0,0 +1,34 @@ +TransportType=DME2 +Latitude =47.778998 +Longitude =-122.182883 +Version =1.0 +ServiceName =dmaap-v1.dev.dmaap.dt.saat.acsi.att.com/events +Environment =TEST +Partner = +SubContextPath =/ +Protocol =https +MethodType =GET +username =test +password =test +contenttype =application/json +authKey=ABC123 +authDate=2016-05-10T13:13:50-0700 +host=localhost:3904 +topic=ccsdk-topic +group=pserver +id=1 +timeout=20000 +limit=10000 +filter={"class":"Equals","field":"event-header.entity-type","value":"pserver"} +AFT_DME2_EXCHANGE_REQUEST_HANDLERS=com.att.nsa.test.PreferredRouteRequestHandler +AFT_DME2_EXCHANGE_REPLY_HANDLERS=com.att.nsa.test.PreferredRouteReplyHandler +AFT_DME2_REQ_TRACE_ON=true +AFT_ENVIRONMENT=AFTUAT +AFT_DME2_EP_CONN_TIMEOUT=55000 +AFT_DME2_ROUNDTRIP_TIMEOUT_MS=240000 +AFT_DME2_EP_READ_TIMEOUT_MS=50000 +sessionstickinessrequired=NO +DME2preferredRouterFilePath=src/test/resources/dmaap-listener.preferredRoute.txt +sdnc.odl.user=admin +sdnc.odl.password=admin +sdnc.odl.url-base=http://localhost:8181/restconf/operations \ No newline at end of file -- cgit 1.2.3-korg