diff options
Diffstat (limited to 'src')
104 files changed, 12993 insertions, 0 deletions
diff --git a/src/main/assembly/descriptor.xml b/src/main/assembly/descriptor.xml new file mode 100644 index 0000000..094d8fb --- /dev/null +++ b/src/main/assembly/descriptor.xml @@ -0,0 +1,32 @@ +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> + <id>build</id> + <includeBaseDirectory>false</includeBaseDirectory> + <formats> + <format>dir</format> + </formats> + <fileSets> + <fileSet> + <directory>${project.basedir}/src/main/resources</directory> + <outputDirectory>/resources</outputDirectory> + <includes> + <include>**/*</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.basedir}/src/main/scripts</directory> + <outputDirectory>/bin</outputDirectory> + <includes> + <include>*</include> + </includes> + </fileSet> + <fileSet> + <directory>${project.build.directory}</directory> + <outputDirectory>/lib</outputDirectory> + <includes> + <include>${project.artifactId}-${project.version}.jar</include> + </includes> + </fileSet> + </fileSets> +</assembly> diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile new file mode 100644 index 0000000..eb49a7d --- /dev/null +++ b/src/main/docker/Dockerfile @@ -0,0 +1,22 @@ +FROM aaionap/aai-common:1.3.0 + +# Add the proper files into the docker image from your build +WORKDIR /opt/app/aai-cacher + +# Expose the ports for outside linux to use +# 8444 is the important one to be used +EXPOSE 8444 + +HEALTHCHECK --interval=40s --timeout=10s --retries=3 CMD nc -z -v localhost 8444 || exit 1 + +ENTRYPOINT ["/bin/bash", "/opt/app/aai-cacher/docker-entrypoint.sh"] + +RUN mkdir -p /opt/aaihome/aaiadmin /opt/aai/logroot/AAI-CACHER + +VOLUME /opt/aai/logroot/AAI-CACHER +VOLUME /opt/aaihome +VOLUME /opt/aaihome/aaiadmin + +COPY /maven/aai-cacher/ . + +ENV AAI_BUILD_VERSION @aai.docker.version@
\ No newline at end of file diff --git a/src/main/docker/aai.sh b/src/main/docker/aai.sh new file mode 100644 index 0000000..cd496f1 --- /dev/null +++ b/src/main/docker/aai.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# ============LICENSE_START======================================================= +# org.onap.aai +# ================================================================================ +# Copyright © 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========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +# + +PROJECT_HOME=/opt/app/aai-cacher +export PROJECT_HOME + +JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 +export JAVA_HOME + +AAIENV=dev +export AAIENV + +PATH=/usr/lib/jvm/java-8-openjdk-amd64:$PATH + +PROJECT_OWNER=aaiadmin +PROJECT_GROUP=aaiadmin +PROJECT_UNIXHOMEROOT=/opt/aaihome +export PROJECT_OWNER PROJECT_GROUP PROJECT_UNIXHOMEROOT +umask 0022 + +export idns_api_url= +export idnscred= +export idnstenant= + diff --git a/src/main/docker/docker-entrypoint.sh b/src/main/docker/docker-entrypoint.sh new file mode 100644 index 0000000..06fd7f4 --- /dev/null +++ b/src/main/docker/docker-entrypoint.sh @@ -0,0 +1,125 @@ +#!/bin/bash + +APP_HOME=$(pwd); +RESOURCES_HOME=${APP_HOME}/resources/; + +export CHEF_CONFIG_REPO=${CHEF_CONFIG_REPO:-aai-config}; +export CHEF_GIT_URL=${CHEF_GIT_URL:-http://gerrit.onap.org/r/aai}; +export CHEF_CONFIG_GIT_URL=${CHEF_CONFIG_GIT_URL:-$CHEF_GIT_URL}; +export CHEF_DATA_GIT_URL=${CHEF_DATA_GIT_URL:-$CHEF_GIT_URL}; + +export SERVER_PORT=${SERVER_PORT:-8444}; + +USER_ID=${LOCAL_USER_ID:-9001} +GROUP_ID=${LOCAL_GROUP_ID:-9001} + +# need to override this in docker compose template to use proxy +PROXY_HOST=${LOCAL_PROXY_HOST:-} + +echo "APPHOME is $APP_HOME"; + +if [ $(cat /etc/passwd | grep aaiadmin | wc -l) -eq 0 ]; then + groupadd aaiadmin -g ${GROUP_ID} || { + echo "Unable to create the group id for ${GROUP_ID}"; + exit 1; + } + useradd --shell=/bin/bash -u ${USER_ID} -g ${GROUP_ID} -o -c "" -m aaiadmin || { + echo "Unable to create the user id for ${USER_ID}"; + exit 1; + } +fi; + +chown -R aaiadmin:aaiadmin /opt/app /opt/aai/logroot /var/chef +find /opt/app/ -name "*.sh" -exec chmod +x {} + + +gosu aaiadmin ln -s bin scripts +gosu aaiadmin ln -s /opt/aai/logroot/AAI-CACHER logs +mkdir -p /opt/app/aai-cacher/logs/gc +chown -R aaiadmin:aaiadmin /opt/app/aai-cacher/logs + +if [ -f ${APP_HOME}/aai.sh ]; then + mv ${APP_HOME}/aai.sh /etc/profile.d/aai.sh + chmod 755 /etc/profile.d/aai.sh + + scriptName=$1; + + if [ ! -z $scriptName ]; then + + if [ -f ${APP_HOME}/bin/${scriptName} ]; then + shift 1; + gosu aaiadmin ${APP_HOME}/bin/${scriptName} "$@" || { + echo "Failed to run the ${scriptName}"; + exit 1; + } + else + echo "Unable to find the script ${scriptName} in ${APP_HOME}/bin"; + exit 1; + fi; + + exit 0; + fi; +fi; + +if [ -f ${APP_HOME}/scripts/install/cacher-swm-vars.sh ]; then + source ${APP_HOME}/scripts/install/cacher-swm-vars.sh; +fi; + +MIN_HEAP_SIZE=${MIN_HEAP_SIZE:-512m}; +MAX_HEAP_SIZE=${MAX_HEAP_SIZE:-1024m}; +MAX_PERM_SIZE=${MAX_PERM_SIZE:-512m}; +PERM_SIZE=${PERM_SIZE:-512m}; + +JAVA_CMD="exec gosu aaiadmin java"; + +JVM_OPTS="${PRE_JVM_ARGS} -Xloggc:/opt/app/aai-cacher/logs/gc/aai_gc.log"; +JVM_OPTS="${JVM_OPTS} -XX:HeapDumpPath=/opt/app/aai-cacher/logs/ajsc-jetty/heap-dump"; +JVM_OPTS="${JVM_OPTS} -Xms${MIN_HEAP_SIZE}"; +JVM_OPTS="${JVM_OPTS} -Xmx${MAX_HEAP_SIZE}"; + +JVM_OPTS="${JVM_OPTS} -XX:+PrintGCDetails"; +JVM_OPTS="${JVM_OPTS} -XX:+PrintGCTimeStamps"; +JVM_OPTS="${JVM_OPTS} -XX:MaxPermSize=${MAX_PERM_SIZE}"; +JVM_OPTS="${JVM_OPTS} -XX:PermSize=${PERM_SIZE}"; + +JVM_OPTS="${JVM_OPTS} -server"; +JVM_OPTS="${JVM_OPTS} -XX:NewSize=512m"; +JVM_OPTS="${JVM_OPTS} -XX:MaxNewSize=512m"; +JVM_OPTS="${JVM_OPTS} -XX:SurvivorRatio=8"; +JVM_OPTS="${JVM_OPTS} -XX:+DisableExplicitGC"; +JVM_OPTS="${JVM_OPTS} -verbose:gc"; +JVM_OPTS="${JVM_OPTS} -XX:+UseParNewGC"; +JVM_OPTS="${JVM_OPTS} -XX:+CMSParallelRemarkEnabled"; +JVM_OPTS="${JVM_OPTS} -XX:+CMSClassUnloadingEnabled"; +JVM_OPTS="${JVM_OPTS} -XX:+UseConcMarkSweepGC"; +JVM_OPTS="${JVM_OPTS} -XX:-UseBiasedLocking"; +JVM_OPTS="${JVM_OPTS} -XX:ParallelGCThreads=4"; +JVM_OPTS="${JVM_OPTS} -XX:LargePageSizeInBytes=128m"; +JVM_OPTS="${JVM_OPTS} -XX:+PrintGCDetails"; +JVM_OPTS="${JVM_OPTS} -XX:+PrintGCTimeStamps"; +JVM_OPTS="${JVM_OPTS} -Dsun.net.inetaddr.ttl=180"; +JVM_OPTS="${JVM_OPTS} -XX:+HeapDumpOnOutOfMemoryError"; +JVM_OPTS="${JVM_OPTS} ${POST_JVM_ARGS}"; +JVM_OPTS="${JVM_OPTS} -Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true"; + +JAVA_OPTS="${JAVA_OPTS} -DAJSC_HOME=$APP_HOME"; +if [ -f ${INTROSCOPE_LIB}/Agent.jar ] && [ -f ${INTROSCOPE_AGENTPROFILE} ]; then + JAVA_OPTS="${JAVA_OPTS} -javaagent:${INTROSCOPE_LIB}/Agent.jar -noverify -Dcom.wily.introscope.agentProfile=${INTROSCOPE_AGENTPROFILE} -Dintroscope.agent.agentName=cacher" +fi +JAVA_OPTS="${JAVA_OPTS} -Dserver.port=${SERVER_PORT}"; +JAVA_OPTS="${JAVA_OPTS} -DBUNDLECONFIG_DIR=./resources"; +JAVA_OPTS="${JAVA_OPTS} -Dserver.local.startpath=${RESOURCES_HOME}"; +JAVA_OPTS="${JAVA_OPTS} -DAAI_CHEF_ENV=${AAI_CHEF_ENV}"; +JAVA_OPTS="${JAVA_OPTS} -DSCLD_ENV=${SCLD_ENV}"; +JAVA_OPTS="${JAVA_OPTS} -DAFT_ENVIRONMENT=${AFT_ENVIRONMENT}"; +JAVA_OPTS="${JAVA_OPTS} -DAAI_BUILD_VERSION=${AAI_BUILD_VERSION}"; +JAVA_OPTS="${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom"; +JAVA_OPTS="${JAVA_OPTS} -Dlogback.configurationFile=./resources/logback.xml"; +JAVA_OPTS="${JAVA_OPTS} -Dloader.path=$APP_HOME/resources"; +if [ ! -z ${PROXY_HOST} ]; then + JAVA_OPTS="${JAVA_OPTS} -DproxySet=true -DproxyHost=${PROXY_HOST} -DproxyPort=8080"; +fi +JAVA_OPTS="${JAVA_OPTS} ${POST_JAVA_OPTS}"; + +JAVA_MAIN_JAR=$(ls lib/aai-cacher*.jar); + +${JAVA_CMD} ${JVM_OPTS} ${JAVA_OPTS} -jar ${JAVA_MAIN_JAR};
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/Application.java b/src/main/java/org/onap/aai/cacher/Application.java new file mode 100644 index 0000000..9382f4b --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/Application.java @@ -0,0 +1,85 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher; + +import org.onap.aai.cacher.config.PropertyPasswordConfiguration; +import org.onap.aai.logging.LoggingContext; +import org.onap.aai.logging.LoggingContext.StatusCode; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.support.SpringBootServletInitializer; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.PropertySource; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.UUID; + +@SpringBootApplication +@EnableScheduling +@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class }) +@ComponentScan(basePackages = { "org.onap.aai.cacher", "com" }) +@PropertySource("classpath:application.properties") +public class Application extends SpringBootServletInitializer { + private static final String APP_NAME = "cacher"; + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(Application.class); + } + + public static void main(String[] args) throws Exception { + setDefaultProps(); + + LoggingContext.save(); + LoggingContext.component("init"); + LoggingContext.partnerName("NA"); + LoggingContext.targetEntity(APP_NAME); + LoggingContext.requestId(UUID.randomUUID().toString()); + LoggingContext.serviceName(APP_NAME); + LoggingContext.targetServiceName("contextInitialized"); + LoggingContext.statusCode(StatusCode.COMPLETE); + + SpringApplication app = new SpringApplication(Application.class); + app.setLogStartupInfo(false); + app.setRegisterShutdownHook(true); + app.addInitializers(new PropertyPasswordConfiguration()); + app.run(args); + + } + + public static void setDefaultProps() { + + if (System.getProperty("file.separator") == null) { + System.setProperty("file.separator", "/"); + } + + if (System.getProperty("AJSC_HOME") == null) { + System.setProperty("AJSC_HOME", "."); + } + + if (System.getProperty("BUNDLECONFIG_DIR") == null) { + System.setProperty("BUNDLECONFIG_DIR", "src/main/resources"); + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/Profiles.java b/src/main/java/org/onap/aai/cacher/Profiles.java new file mode 100644 index 0000000..05c3559 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/Profiles.java @@ -0,0 +1,31 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher; + +public final class Profiles { + + public static final String DMAAP = "dmaap"; + public static final String DME2 = "dme2"; + + public static final String ONE_WAY_SSL = "one-way-ssl"; + public static final String TWO_WAY_SSL = "two-way-ssl"; + + private Profiles(){} +} diff --git a/src/main/java/org/onap/aai/cacher/common/CacheKeyConfig.java b/src/main/java/org/onap/aai/cacher/common/CacheKeyConfig.java new file mode 100644 index 0000000..e02ea81 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/common/CacheKeyConfig.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.common; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.onap.aai.cacher.model.CacheKey; + +import java.util.ArrayList; +import java.util.List; + +public class CacheKeyConfig { + private JsonArray cachekeys = null; + + private static final String CACHEKEYS = "cachekeys"; + + public CacheKeyConfig(String json) { + init(json); + } + + private void init(String json) { + JsonParser parser = new JsonParser(); + JsonObject queriesObject = parser.parse(json).getAsJsonObject(); + if (queriesObject.has(CACHEKEYS)) { + cachekeys = queriesObject.getAsJsonArray(CACHEKEYS); + } + } + + public List<CacheKey> populateCacheKeyList() { + List<CacheKey> ckList = new ArrayList<>(); + for (JsonElement cacheKeyElement : cachekeys) { + if (cacheKeyElement.isJsonObject()) { + JsonObject cacheJsonObj = cacheKeyElement.getAsJsonObject(); + if (cacheJsonObj != null) { + CacheKey cacheKey = CacheKey.fromJson(cacheJsonObj); + ckList.add(cacheKey); + } + } + } + return ckList; + } + +} diff --git a/src/main/java/org/onap/aai/cacher/common/MongoConfig.java b/src/main/java/org/onap/aai/cacher/common/MongoConfig.java new file mode 100644 index 0000000..d08930b --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/common/MongoConfig.java @@ -0,0 +1,104 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.common; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoDatabase; +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodProcess; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import java.io.IOException; + +@Configuration +public class MongoConfig { + + private final static EELFLogger EELF_LOGGER = EELFManager.getInstance().getLogger(MongoConfig.class); + + @Value("${mongodb.host}") + private String MONGO_DB_HOST; + @Value("${mongodb.dbName}") + private String MONGO_DB_NAME; + @Value("${mongodb.port}") + private int MONGO_DB_PORT; + + @Bean + public MongoClient mongoClient() { + try { + // To connect to mongodb server + MongoClient mongoC = new MongoClient(MONGO_DB_HOST, MONGO_DB_PORT); + + // Now connect to your databases + EELF_LOGGER.info("Connect to database successfully"); + + return mongoC; + + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000"); + ErrorLogHelper.logException(aaiException); + } + + return null; + } + + @Bean + public DB db(MongoClient mongoClient) { + return mongoClient.getDB(MONGO_DB_NAME); + } + + @Bean + public MongoDatabase mongoDatabase(MongoClient mongoClient) { + return mongoClient.getDatabase(MONGO_DB_NAME); + } + + @Bean + @PostConstruct + public MongodProcess mongoEmbedded() throws IOException, InterruptedException { + + MongodStarter starter = MongodStarter.getDefaultInstance(); + + String bindIp = MONGO_DB_HOST; + int port = MONGO_DB_PORT; + IMongodConfig mongodConfig = new MongodConfigBuilder().version(Version.Main.PRODUCTION) + .net(new Net(port, Network.localhostIsIPv6())).configServer(false).build(); + + MongodExecutable mongodExecutable = starter.prepare(mongodConfig); + // Thread.sleep(20000L); + MongodProcess mongod = mongodExecutable.start(); + if (mongod.isProcessRunning()) { + System.out.println("RUNNING"); + } + return mongod; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/common/MongoHelperSingleton.java b/src/main/java/org/onap/aai/cacher/common/MongoHelperSingleton.java new file mode 100644 index 0000000..63638f1 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/common/MongoHelperSingleton.java @@ -0,0 +1,312 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.common; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.collect.Lists; +import com.google.gson.JsonObject; +import com.mongodb.*; +import com.mongodb.client.AggregateIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.DBCollectionUpdateOptions; +import com.mongodb.client.model.FindOneAndUpdateOptions; +import com.mongodb.client.model.UpdateOptions; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import org.apache.commons.lang3.StringUtils; +import org.bson.Document; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Creates and returns a mongo instance + */ + +@Component +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class MongoHelperSingleton { + + private final static EELFLogger EELF_LOGGER = EELFManager.getInstance().getLogger(MongoHelperSingleton.class); + + private DB db; + + private MongoDatabase mongoDatabase; + + @Autowired + public MongoHelperSingleton(DB db, MongoDatabase mongoDatabase) { + this.mongoDatabase = mongoDatabase; + this.db = db; + } + + public DB getDb() { + return db; + } + + public void createCollection(String name) { + try { + db.getCollection(name); + EELF_LOGGER.info("Collection " + name + " created successfully"); + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000"); + ErrorLogHelper.logException(aaiException); + } + } + + public boolean addToMongo(String collectionName, Object document) { + try { + DBCollection collection = db.getCollection(collectionName); + WriteResult result; + if (document instanceof List) { + result = collection.insert((List<BasicDBObject>) document); + return result.wasAcknowledged(); + } else if (document instanceof BasicDBObject) { + result = collection.insert((BasicDBObject) document); + return result.wasAcknowledged(); + } else { + EELF_LOGGER.error("The cachekey object to add was of unknown type"); + return false; + } + } catch (MongoException ex) { + AAIException aaiException = new AAIException("AAI_5105"); + ErrorLogHelper.logException(aaiException); + return false; + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000"); + ErrorLogHelper.logException(aaiException); + return false; + } + } + + public boolean updateInMongo(String collectionName, BasicDBObject searchQuery, Object document, + DBCollectionUpdateOptions updateOptions) { + try { + DBCollection collection = db.getCollection(collectionName); + WriteResult result; + result = collection.update(searchQuery, (BasicDBObject) document, updateOptions); + return result.wasAcknowledged(); + } catch (MongoException ex) { + AAIException aaiException = new AAIException("AAI_5105"); + ErrorLogHelper.logException(aaiException); + return false; + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000"); + ErrorLogHelper.logException(aaiException); + return false; + } + } + + public String deleteFromMongo(String collectionName, Map<String, String> whereClause) { + DBCollection collection = db.getCollection(collectionName); + DBObject searchQuery = new BasicDBObject(); + for (Map.Entry<String, String> entry : whereClause.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + searchQuery.put(key, value); + } + try { + WriteResult result = collection.remove(searchQuery); + if (result.getN() > 0) { + return "DELETED"; + } else { + return "NOT_FOUND"; + } + } catch (MongoException ex) { + AAIException aaiException = new AAIException("AAI_5105"); + ErrorLogHelper.logException(aaiException); + return "EXCEPTION_THROWN"; + } + } + + public void dropCollection(String collectionName) { + db.getCollection(collectionName).drop(); + } + + public Response buildResponse(Status status, String result) { + return Response.status(status).type(MediaType.APPLICATION_JSON).entity(result).build(); + } + + public Response buildExceptionResponse(AAIException aaiException) { + ErrorLogHelper.logException(aaiException); + return Response.status(aaiException.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging( + Lists.newArrayList(MediaType.APPLICATION_JSON_TYPE), aaiException, new ArrayList<>())) + .build(); + } + + public boolean insertReplace(CacheEntry cacheEntry) { + MongoCollection<Document> collection = mongoDatabase.getCollection(cacheEntry.getCollection()); + + Document findQuery = Document.parse(cacheEntry.getFindQuery().toString()); + Document payload = Document.parse(cacheEntry.getPayload().toString()); + + if (!cacheEntry.isNested()) { + UpdateResult updateResult = collection.replaceOne(findQuery, payload, new UpdateOptions().upsert(true)); + + return updateResult.wasAcknowledged(); + } else { + CacheEntry localCacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry().deepCopy(cacheEntry).build(); + Document nestedFind = Document.parse(localCacheEntry.getNestedFind().toString()); + + // if exists remove + if (collection.count(nestedFind) > 0L) { + mongoPull(localCacheEntry, collection, nestedFind); + } + + ArrayList<Document> filters = this.getFiltersAndUpdateNestedField(localCacheEntry); + Document doc = new Document(); + doc.put(localCacheEntry.getNestedField(), payload); + Document push = new Document(); + push.put("$push", doc); + + collection.findOneAndUpdate(findQuery, push, + new FindOneAndUpdateOptions().arrayFilters(filters).upsert(true)); + + return collection.count(nestedFind) > 0L; + } + } + + public boolean delete(CacheEntry cacheEntry) { + + MongoCollection<Document> collection = mongoDatabase.getCollection(cacheEntry.getCollection()); + + Document findQuery = Document.parse(cacheEntry.getFindQuery().toString()); + + if (!cacheEntry.isNested()) { + if (collection.count(findQuery) == 0L) { + return true; + } + DeleteResult deleteResult = collection.deleteOne(findQuery); + return deleteResult.wasAcknowledged(); + + } else { + Document nestedFind = Document.parse(cacheEntry.getNestedFind().toString()); + if (collection.count(nestedFind) == 0L) { + return true; + } + + mongoPull(cacheEntry, collection, nestedFind); + return collection.count(nestedFind) == 0L; + + } + } + + public Optional<Document> getObject(CacheEntry cacheEntry) { + MongoCollection<Document> collection = mongoDatabase.getCollection(cacheEntry.getCollection()); + Document resultingObject; + + if (!cacheEntry.isNested()) { + resultingObject = collection.find(Document.parse(cacheEntry.getFindQuery().toString())).first(); + } else { + List<Document> aggregate = getAggregateFromFind(cacheEntry.getNestedFind()); + AggregateIterable<Document> aggregateResult = collection.aggregate(aggregate); + resultingObject = aggregateResult.first(); + if (resultingObject != null) { + resultingObject = (Document) (resultingObject.get("output")); + } + } + + return Optional.ofNullable(resultingObject); + } + + private List<Document> getAggregateFromFind(JsonObject nestedFind) { + Document nestedFindDocument = Document.parse(nestedFind.toString()); + List<Document> aggregate = new ArrayList<>(); + List<String> keys = new ArrayList<>(nestedFindDocument.keySet()); + for (int i = 0; i < keys.size(); i++) { + if (!keys.get(i).contains(".")) { + aggregate.add(new Document("$match", new Document(keys.get(i), nestedFindDocument.get(keys.get(i))))); + } else { + aggregate.add(new Document("$unwind", "$" + keys.get(i).substring(0, keys.get(i).lastIndexOf('.')))); + aggregate.add(new Document("$match", new Document(keys.get(i), nestedFindDocument.get(keys.get(i))))); + } + if (i == keys.size() - 1) { + aggregate.add(new Document("$project", new Document("_id", 0).append("output", + "$" + keys.get(i).substring(0, keys.get(i).lastIndexOf('.'))))); + } + } + return aggregate; + } + + protected void mongoPull(CacheEntry cacheEntry, MongoCollection<Document> collection, Document nestedFind) { + CacheEntry localCacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry().deepCopy(cacheEntry).build(); + ArrayList<Document> filters = this.getFiltersAndUpdateNestedField(localCacheEntry); + + Document pullObj = new Document(); + pullObj.put(localCacheEntry.getNestedField(), + Document.parse(localCacheEntry.getNestedFieldIdentifierObj().toString())); + Document pull = new Document(); + pull.put("$pull", pullObj); + collection.findOneAndUpdate(nestedFind, pull, new FindOneAndUpdateOptions().arrayFilters(filters).upsert(true)); + // TODO remove wrapping if there are no entries in array. + + } + + private ArrayList<Document> getFiltersAndUpdateNestedField(CacheEntry cacheEntry) { + + if (StringUtils.countMatches(cacheEntry.getNestedField(), ".$.") < 2) { + return new ArrayList<>(); + } + + ArrayList<Document> filters = new ArrayList<>(); + List<String> keys = cacheEntry.getNestedFind().entrySet().stream().map(Map.Entry::getKey) + .filter(s -> !s.equals("_id")).sorted((s, t1) -> { + if (StringUtils.countMatches(s, ".") > StringUtils.countMatches(t1, ".")) { + return 1; + } + return s.compareTo(t1); + }).collect(Collectors.toList()); + String filterKey; + String filterValue; + String key; + char filterIndex = 'a'; + StringBuilder newNestedField = new StringBuilder(); + List<String> fieldSplit = Arrays.asList(cacheEntry.getNestedField().split("\\.\\$")); + for (int i = 0; i < fieldSplit.size(); i++) { + final String subSplit = StringUtils.join(fieldSplit.subList(0, i + 1), ""); + key = keys.stream().filter(s -> s.startsWith(subSplit)).findFirst().get(); + filterIndex += i; + filterKey = filterIndex + "." + key.substring(key.lastIndexOf(".") + 1); + filterValue = cacheEntry.getNestedFind().get(key).getAsString(); + newNestedField.append(fieldSplit.get(i)); + if (i + 1 != fieldSplit.size()) { + newNestedField.append(".$[").append(filterIndex).append("]"); + filters.add(new Document().append(filterKey, filterValue)); + } + + } + cacheEntry.setNestedField(newNestedField.toString()); + + return filters; + } + +} diff --git a/src/main/java/org/onap/aai/cacher/config/JettyPasswordDecoder.java b/src/main/java/org/onap/aai/cacher/config/JettyPasswordDecoder.java new file mode 100644 index 0000000..ef18883 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/config/JettyPasswordDecoder.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.config; + +import org.eclipse.jetty.util.security.Password; + +public class JettyPasswordDecoder implements PasswordDecoder { + + @Override + public String decode(String input) { + if (input.startsWith("OBF:")) { + return Password.deobfuscate(input); + } + return Password.deobfuscate("OBF:" + input); + } +} diff --git a/src/main/java/org/onap/aai/cacher/config/PasswordDecoder.java b/src/main/java/org/onap/aai/cacher/config/PasswordDecoder.java new file mode 100644 index 0000000..053e3e8 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/config/PasswordDecoder.java @@ -0,0 +1,25 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.config; + +public interface PasswordDecoder { + + String decode(String input); +} diff --git a/src/main/java/org/onap/aai/cacher/config/PropertyPasswordConfiguration.java b/src/main/java/org/onap/aai/cacher/config/PropertyPasswordConfiguration.java new file mode 100644 index 0000000..27a43e2 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/config/PropertyPasswordConfiguration.java @@ -0,0 +1,80 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.config; + +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PropertyPasswordConfiguration implements ApplicationContextInitializer<ConfigurableApplicationContext> { + + private static final Pattern decodePasswordPattern = Pattern.compile("password\\((.*?)\\)"); + + private PasswordDecoder passwordDecoder = new JettyPasswordDecoder(); + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + ConfigurableEnvironment environment = applicationContext.getEnvironment(); + for (PropertySource<?> propertySource : environment.getPropertySources()) { + Map<String, Object> propertyOverrides = new LinkedHashMap<>(); + decodePasswords(propertySource, propertyOverrides); + if (!propertyOverrides.isEmpty()) { + PropertySource<?> decodedProperties = new MapPropertySource("decoded " + propertySource.getName(), + propertyOverrides); + environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties); + } + } + } + + private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) { + if (source instanceof EnumerablePropertySource) { + EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source; + for (String key : enumerablePropertySource.getPropertyNames()) { + Object rawValue = source.getProperty(key); + if (rawValue instanceof String) { + String decodedValue = decodePasswordsInString((String) rawValue); + propertyOverrides.put(key, decodedValue); + } + } + } + } + + private String decodePasswordsInString(String input) { + if (input == null) + return null; + StringBuffer output = new StringBuffer(); + Matcher matcher = decodePasswordPattern.matcher(input); + while (matcher.find()) { + String replacement = passwordDecoder.decode(matcher.group(1)); + matcher.appendReplacement(output, replacement); + } + matcher.appendTail(output); + return output.toString(); + } + +} diff --git a/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessor.java b/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessor.java new file mode 100644 index 0000000..5c684a2 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessor.java @@ -0,0 +1,175 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mongodb.MongoCommandException; +import org.bson.Document; +import org.json.JSONException; +import org.json.JSONObject; +import org.onap.aai.cacher.common.MongoHelperSingleton; +import org.onap.aai.cacher.injestion.parser.PayloadParserService; +import org.onap.aai.cacher.injestion.parser.strategy.PayloadParserType; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class AAIDmaapEventProcessor implements DmaapProcessor { + + private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIEventConsumer.class); + + private final JsonParser parser = new JsonParser(); + + private JSONObject event; + private JSONObject eventHeader; + private JSONObject eventBody; + + private MongoHelperSingleton mongoHelper; + private PayloadParserService payloadParserService; + + @Autowired + public AAIDmaapEventProcessor(MongoHelperSingleton mongoHelper, PayloadParserService payloadParserService) { + this.mongoHelper = mongoHelper; + this.payloadParserService = payloadParserService; + } + + public AAIDmaapEventProcessor() { + } + + /** + * + * @param eventMessage + * @return + */ + public void process(String eventMessage) throws Exception { + this.event = null; + this.eventHeader = null; + this.eventBody = null; + + try { + LOGGER.debug("Processing event: " + eventMessage); + this.event = new JSONObject(eventMessage); + } catch (JSONException je) { + LOGGER.error("ERROR: Event is not valid JSON [" + eventMessage + "]."); + ErrorLogHelper.logException(new AAIException("AAI_4000", je)); + throw je; + } + + try { + LOGGER.debug("Validating event header."); + this.validateEventHeader(this.event); + } catch (JSONException je) { + LOGGER.error("ERROR: Event header is not valid [" + eventMessage + "]."); + ErrorLogHelper.logException(new AAIException("AAI_4000", je)); + throw je; + } + + try { + LOGGER.debug("Processing entity."); + eventBody = this.event.getJSONObject("entity"); + } catch (JSONException je) { + LOGGER.error("ERROR: Event body is not valid JSON [" + eventMessage + "]."); + ErrorLogHelper.logException(new AAIException("AAI_4000", je)); + throw je; + } + + List<CacheEntry> dmaapCacheEntries = payloadParserService.doParse("aai-dmaap", + parser.parse(eventMessage).getAsJsonObject(), PayloadParserType.AAI_RESOURCE_DMAAP); + + // Get existing object if is update + Optional<Document> existingObj = Optional.empty(); + if (this.eventHeader != null && "UPDATE".equals(eventHeader.getString("action"))) { + existingObj = mongoHelper.getObject(dmaapCacheEntries.get(0)); + } + + // Add existing object to payload to be parsed by AAI_RESOURCE_DMAAP parser + if (existingObj.isPresent()) { + JsonObject eventMessageObj = parser.parse(eventMessage).getAsJsonObject(); + eventMessageObj.add("existing-obj", parser.parse(existingObj.get().toJson()).getAsJsonObject()); + eventMessage = eventMessageObj.toString(); + dmaapCacheEntries = payloadParserService.doParse("aai-dmaap", parser.parse(eventMessage).getAsJsonObject(), + PayloadParserType.AAI_RESOURCE_DMAAP); + } + + for (CacheEntry cacheEntry : dmaapCacheEntries) { + try { + switch (cacheEntry.getDbAction()) { + case DELETE: + mongoHelper.delete(cacheEntry); + break; + case UPDATE: + mongoHelper.insertReplace(cacheEntry); + break; + case INSERT_REPLACE: + mongoHelper.insertReplace(cacheEntry); + break; + } + } catch (MongoCommandException exception) { + LOGGER.warn("Attempted to update nested that does not exist in cache.", exception); + } + } + + LOGGER.debug("Event processed successfully."); + + } + + /** + * Validates that the event header has the id and source name for processing. + * (needed for status response msg) + * + * @param event + * @throws JSONException + */ + private void validateEventHeader(JSONObject event) throws JSONException { + eventHeader = event.getJSONObject("event-header"); + if (this.eventHeader.getString("id") == null || this.eventHeader.getString("id").isEmpty()) { + throw new JSONException("Event header id missing."); + } else if (this.eventHeader.getString("source-name") == null + || this.eventHeader.getString("source-name").isEmpty()) { + throw new JSONException("Event header source-name missing."); + } + } + + /** + * + * @return + */ + public JSONObject getEventHeader() { + return eventHeader; + } + + /** + * + * @return + */ + public JSONObject getEventBody() { + return eventBody; + } + +} diff --git a/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIEventConsumer.java b/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIEventConsumer.java new file mode 100644 index 0000000..cb1c77a --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIEventConsumer.java @@ -0,0 +1,34 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +public class AAIEventConsumer extends AAIParentEventConsumer { + + private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIEventConsumer.class); + + public AAIEventConsumer(String consumerPropFile, boolean injestConsumer) throws Exception { + super(consumerPropFile, injestConsumer); + LOGGER.debug("Initialization completed."); + } + +} diff --git a/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIParentEventConsumer.java b/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIParentEventConsumer.java new file mode 100644 index 0000000..8d64116 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/dmaap/consumer/AAIParentEventConsumer.java @@ -0,0 +1,237 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.att.nsa.mr.client.MRClientFactory; +import com.att.nsa.mr.client.MRConsumer; +import org.apache.commons.configuration.ConfigurationException; +import org.eclipse.jetty.util.security.Password; +import org.onap.aai.cacher.util.AAIConstants; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.util.AAIConfig; + +import java.io.*; +import java.util.Properties; +import java.util.UUID; +import java.util.logging.Level; + +public class AAIParentEventConsumer { + + protected String fromAppId = "AAIEventConsumerScheduledTask"; + protected String COMPONENT = "DMAAP-AAI-EVENT"; + private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIParentEventConsumer.class); + + protected String preferredRouterFilePath; + protected String aaiDmaapEventConsumerPropertiesFile; + + protected String dmaapPropertyHome = ""; + protected String dmaapConusmerId = ""; + protected String transId = ""; + + protected Properties aaiDmaapEventConsumerProperties = new Properties(); + + protected MRConsumer aaiDmaapEventConsumer; + + protected DmaapConsumerSingleton dmaapConsumerSingleton; + + /* + * Change the client consumer implementation from RestDmaapClientConsumer to + * DmaapClientConsumer when the bug that is making dme2 connections in dev, + * testINT, testEXT is fixed + */ + protected ClientConsumer clientConsumer; + + public AAIParentEventConsumer(String consumerPropFile, boolean injestConsumer) throws Exception { + this.transId = UUID.randomUUID().toString(); + LOGGER.debug("Initalize the AAIParentEventConsumer"); + + DmaapConsumerSingleton dmaapConsumerSingleton = DmaapConsumerSingleton.getInstance(); + + this.dmaapPropertyHome = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES; + + if (dmaapConsumerSingleton.getDmaapConsumerId() == null) { + dmaapConsumerSingleton.setDmaapConsumerId(UUID.randomUUID().toString()); + } + this.dmaapConusmerId = dmaapConsumerSingleton.getDmaapConsumerId(); + + processPropertyFiles(consumerPropFile); + if (!injestConsumer) { + this.aaiDmaapEventConsumer = MRClientFactory.createConsumer(this.aaiDmaapEventConsumerProperties.toString()); + setConsumer(aaiDmaapEventConsumer); + } + LOGGER.debug("Initialization completed."); + + } + + public void setConsumer(MRConsumer aaiDmaapEventConsumer) { + this.aaiDmaapEventConsumer = aaiDmaapEventConsumer; + this.clientConsumer = new RestDmaapClientConsumer(this.aaiDmaapEventConsumer, + this.aaiDmaapEventConsumerProperties); + } + + public Properties getDmaapEventConsumerProperties() { + return aaiDmaapEventConsumerProperties; + } + + private void processPropertyFiles(String consumerPropFile) throws IOException, ConfigurationException { + + this.preferredRouterFilePath = this.dmaapPropertyHome + "preferredRoute.txt"; + this.aaiDmaapEventConsumerPropertiesFile = this.dmaapPropertyHome + consumerPropFile; + + LOGGER.debug("Preferred router file path: " + this.preferredRouterFilePath); + LOGGER.debug("AAI Dmaap Event Consumer Properties path: " + this.aaiDmaapEventConsumerPropertiesFile); + + File fo = new File(this.preferredRouterFilePath); + if (!fo.exists()) { + FileNotFoundException ex = new FileNotFoundException( + "Dmaap Route file " + preferredRouterFilePath + " does not exist"); + ErrorLogHelper.logException(new AAIException("AAI_4000", ex)); + throw ex; + } + + fo = new File(this.aaiDmaapEventConsumerPropertiesFile); + if (!fo.exists()) { + FileNotFoundException ex = new FileNotFoundException( + "Dmaap consumer property file " + aaiDmaapEventConsumerPropertiesFile + " does not exist."); + ErrorLogHelper.logException(new AAIException("AAI_4000", ex)); + throw ex; + } + + modifyProperties(); + + } + + private void modifyProperties() throws ConfigurationException, IOException { + + try (Reader reader = new FileReader(new File(this.aaiDmaapEventConsumerPropertiesFile))) { + this.aaiDmaapEventConsumerProperties.load(reader); + } + + aaiDmaapEventConsumerProperties.setProperty("id", this.dmaapConusmerId); + LOGGER.debug("Updated " + this.aaiDmaapEventConsumerPropertiesFile + " id " + this.dmaapConusmerId); + + aaiDmaapEventConsumerProperties.setProperty("DME2preferredRouterFilePath", this.preferredRouterFilePath); + if (aaiDmaapEventConsumerProperties.getProperty("password") != null + && aaiDmaapEventConsumerProperties.getProperty("password").startsWith("OBF:")) { + aaiDmaapEventConsumerProperties.setProperty("password", + Password.deobfuscate(aaiDmaapEventConsumerProperties.getProperty("password"))); + } + LOGGER.debug("Updated " + this.aaiDmaapEventConsumerPropertiesFile + " DME2preferredRouterFilePath property to " + + this.preferredRouterFilePath); + + if (getIsInitialCheck()) { + aaiDmaapEventConsumerProperties.setProperty("limit", "1"); + } + LOGGER.debug("Using limit " + aaiDmaapEventConsumerProperties.getProperty("limit")); + LOGGER.debug("Using filter " + aaiDmaapEventConsumerProperties.getProperty("filter")); + } + + public void startProcessing(DmaapProcessor dmaapProcessor) throws Exception { + int fetchFailCounter = 0; + + while (AAIConfig.get("aai.cacher.dmaap.consumer.enableEventProcessing").equals("true")) { + try { + LOGGER.debug("processEvents=" + dmaapConsumerSingleton.getProcessEvents() + " isInitialized=" + + dmaapConsumerSingleton.getIsInitialized()); + if (dmaapConsumerSingleton.getProcessEvents() || !dmaapConsumerSingleton.getIsInitialized()) { + Iterable<String> eventMessages = clientConsumer.process(); + if (dmaapConsumerSingleton.getFirstEventMessage() != null) { + String firstMessage = getFirstMessage(); + if (firstMessage != null) { + LOGGER.debug("Processing held dmaap message from the aaiDmaapEvent topic." + transId); + LOGGER.debug("Processing held dmaap message from the aaiDmaapEvent topic: " + firstMessage); + dmaapProcessor.process(firstMessage); + } + } + for (String eventMessage : eventMessages) { + if (!dmaapConsumerSingleton.getProcessEvents()) { + // hold message until app is ready for dmaap processing + setFirstMessage(eventMessage); + LOGGER.debug("Holding new dmaap message from the aaiDmaapEvent topic: " + eventMessage); + dmaapConsumerSingleton.setIsInitialized(true); + continue; + } + LOGGER.debug("Processing held dmaap message from the aaiDmaapEvent topic: " + eventMessage); + dmaapProcessor.process(eventMessage); + } + fetchFailCounter = 0; + } else { + // not processing events + this.aaiDmaapEventConsumer.close(); + return; + } + break; + } catch (IOException e) { + fetchFailCounter++; + if (fetchFailCounter > 10) { + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + this.aaiDmaapEventConsumer.close(); + throw e; + } + LOGGER.info("ignoring IOException, count is at." + fetchFailCounter); + } catch (Exception e) { + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + + e.printStackTrace(); + this.aaiDmaapEventConsumer.close(); + e.printStackTrace(); + throw e; + } + } + this.aaiDmaapEventConsumer.close(); + } + + /** + * checks on processing events flag + * + * @return + */ + private boolean getIsInitialCheck() { + dmaapConsumerSingleton = DmaapConsumerSingleton.getInstance(); + if (dmaapConsumerSingleton.getProcessEvents()) { + return false; + } + return !dmaapConsumerSingleton.getIsInitialized(); + } + + /** + * used to hold the first event message received before the app is ready to + * process + */ + + private void setFirstMessage(String message) { + dmaapConsumerSingleton.setFirstEventMessage(message); + } + + /** + * used to get the first event message being held before the app is ready to + * process + */ + + private String getFirstMessage() { + String message = dmaapConsumerSingleton.getFirstEventMessage(); + dmaapConsumerSingleton.setFirstEventMessage(null); + return message; + } + +} diff --git a/src/main/java/org/onap/aai/cacher/dmaap/consumer/ClientConsumer.java b/src/main/java/org/onap/aai/cacher/dmaap/consumer/ClientConsumer.java new file mode 100644 index 0000000..eaa341b --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/dmaap/consumer/ClientConsumer.java @@ -0,0 +1,31 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +/** + * Interface that encapsulates the MRConsumer to switch between using just + * MRConsumer or to use MRConsumer with RestClient for environments where dme2 + * is having problems + */ +public interface ClientConsumer { + + Iterable<String> process() throws Exception; + +} diff --git a/src/main/java/org/onap/aai/cacher/dmaap/consumer/DmaapConsumerSingleton.java b/src/main/java/org/onap/aai/cacher/dmaap/consumer/DmaapConsumerSingleton.java new file mode 100644 index 0000000..5c2faa3 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/dmaap/consumer/DmaapConsumerSingleton.java @@ -0,0 +1,77 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +public class DmaapConsumerSingleton { + + private boolean processEvents; + private boolean isInitialized; + + private String dmaapConsumerId; + + private String firstEventMessage; + + private static class Helper { + private static final DmaapConsumerSingleton INSTANCE = new DmaapConsumerSingleton(); + } + + public static DmaapConsumerSingleton getInstance() { + return Helper.INSTANCE; + } + + private DmaapConsumerSingleton() { + processEvents = false; + isInitialized = false; + firstEventMessage = null; + dmaapConsumerId = null; + } + + public void setProcessEvents(boolean processEvents) { + this.processEvents = processEvents; + } + + public boolean getProcessEvents() { + return processEvents; + } + + public void setIsInitialized(boolean isInitialized) { + this.isInitialized = isInitialized; + } + + public boolean getIsInitialized() { + return isInitialized; + } + + public void setFirstEventMessage(String firstEventMessage) { + this.firstEventMessage = firstEventMessage; + } + + public String getFirstEventMessage() { + return firstEventMessage; + } + + public void setDmaapConsumerId(String dmaapConsumerId) { + this.dmaapConsumerId = dmaapConsumerId; + } + + public String getDmaapConsumerId() { + return dmaapConsumerId; + } +} diff --git a/src/main/java/org/onap/aai/cacher/dmaap/consumer/DmaapProcessor.java b/src/main/java/org/onap/aai/cacher/dmaap/consumer/DmaapProcessor.java new file mode 100644 index 0000000..6cb4b82 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/dmaap/consumer/DmaapProcessor.java @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +/** + * <b>DmaapProcessor</b> is the interface to use to process dmaap consumer + * events + * + * Any new topic that needs to be subscribed should implement this interface to + * process the events received by the dmaap publisher + */ +public interface DmaapProcessor { + + void process(String eventMessage) throws Exception; +} diff --git a/src/main/java/org/onap/aai/cacher/dmaap/consumer/RestDmaapClientConsumer.java b/src/main/java/org/onap/aai/cacher/dmaap/consumer/RestDmaapClientConsumer.java new file mode 100644 index 0000000..5839934 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/dmaap/consumer/RestDmaapClientConsumer.java @@ -0,0 +1,80 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.att.nsa.mr.client.MRConsumer; +import org.springframework.http.HttpHeaders; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Base64; +import java.util.Properties; + +/** + * Encapsulates the MRConsumer and invokes it only if the environment is dev, + * testINT, testEXT If its one of those environments, uses the RestClient + */ +public class RestDmaapClientConsumer implements ClientConsumer { + + private MRConsumer aaiDmaapEventConsumer; + + private static final Base64.Encoder base64Encoder = Base64.getEncoder(); + + private HttpHeaders httpHeaders; + private RestTemplate restTemplate; + + private String env; + // private String url; + private UriComponentsBuilder builder; + + private Properties consumerProperties; + + private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(RestDmaapClientConsumer.class); + + public RestDmaapClientConsumer(MRConsumer consumer, Properties aaiDmaapEventConsumerProperties) { + + env = System.getProperty("lrmRO"); + + this.aaiDmaapEventConsumer = consumer; + this.consumerProperties = aaiDmaapEventConsumerProperties; + + } + + /** + * Checks if the environment is null or if the environment starts with dev, + * testEXT, or testINT and then if that is the case, it makes a request to the + * url to subscribe to that topic to retrieve all messages there If it is not + * one of those environments, then it will call the default fetch of messages + * from the MR Consumer + * + * @return a list of messages from the topic + * @throws Exception + */ + @Override + public Iterable<String> process() throws Exception { + + Iterable<String> messages = aaiDmaapEventConsumer.fetch(); + + LOGGER.debug("Finished the consumption of messages from dmaap"); + return messages; + } +} diff --git a/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterFactory.java b/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterFactory.java new file mode 100644 index 0000000..af6384f --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterFactory.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer; + +import org.onap.aai.cacher.egestion.printer.strategy.PayloadPrinterStrategy; +import org.onap.aai.cacher.egestion.printer.strategy.PayloadPrinterType; + +/** + * Factory to get parser strategy based on parser type. + */ +public interface PayloadPrinterFactory { + /** + * + * @param payloadParserType payload parser strategy type to use + * @return + */ + PayloadPrinterStrategy getPayloadPrinterStrategy(PayloadPrinterType payloadParserType); +} diff --git a/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterFactoryConfiguration.java b/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterFactoryConfiguration.java new file mode 100644 index 0000000..abbc30a --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterFactoryConfiguration.java @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.config.ServiceLocatorFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class PayloadPrinterFactoryConfiguration { + + @Bean + public FactoryBean locatorFactoryBean() { + ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean(); + bean.setServiceLocatorInterface(PayloadPrinterFactory.class); + return bean; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterService.java b/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterService.java new file mode 100644 index 0000000..6acea02 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/egestion/printer/PayloadPrinterService.java @@ -0,0 +1,43 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.onap.aai.cacher.egestion.printer.strategy.PayloadPrinterStrategy; +import org.onap.aai.cacher.egestion.printer.strategy.PayloadPrinterType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class PayloadPrinterService { + @Autowired + private PayloadPrinterFactory payloadPrinterFactory; + + public JsonObject createJson(String collectionName, JsonArray jsonArray, PayloadPrinterType payloadParserType) { + PayloadPrinterStrategy printer = payloadPrinterFactory.getPayloadPrinterStrategy(payloadParserType); + return printer.createJson(collectionName, jsonArray); + } + + public JsonObject createJson(String collectionName, JsonArray jsonArray, String parserStrategy) { + return createJson(collectionName, jsonArray, PayloadPrinterType.fromString(parserStrategy + "-printer")); + } + +} diff --git a/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/AAIResourceGetAllPayloadPrinterStrategy.java b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/AAIResourceGetAllPayloadPrinterStrategy.java new file mode 100644 index 0000000..8dfeb0b --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/AAIResourceGetAllPayloadPrinterStrategy.java @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer.strategy; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Component(value = "aai-resource-get-all-printer") +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class AAIResourceGetAllPayloadPrinterStrategy implements PayloadPrinterStrategy { + + /** + * Create a jsonObject from the jsonArray for a specific collection + * + * @param collectionName + * @param jsonArray + * @return + */ + @Override + public JsonObject createJson(String collectionName, JsonArray jsonArray) { + if (jsonArray != null && jsonArray.size() > 0) { + JsonObject jsonObj = new JsonObject(); + jsonObj.add(collectionName, jsonArray); + return jsonObj; + } else { + return null; + } + } +} diff --git a/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/NonePayloadPrinterStrategy.java b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/NonePayloadPrinterStrategy.java new file mode 100644 index 0000000..3aecfe8 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/NonePayloadPrinterStrategy.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer.strategy; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * Default parser strategy that dont not manipulate the payload. + */ +@Component(value = "none-printer") +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class NonePayloadPrinterStrategy implements PayloadPrinterStrategy { + @Override + public JsonObject createJson(String collectionName, JsonArray jsonArray) { + if (jsonArray != null && jsonArray.size() > 0) { + return jsonArray.get(0).getAsJsonObject(); + } else { + return null; + } + } +} diff --git a/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/PayloadPrinterStrategy.java b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/PayloadPrinterStrategy.java new file mode 100644 index 0000000..b6d3f08 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/PayloadPrinterStrategy.java @@ -0,0 +1,28 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer.strategy; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +public interface PayloadPrinterStrategy { + + JsonObject createJson(String collectionName, JsonArray jsonArray); +} diff --git a/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/PayloadPrinterType.java b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/PayloadPrinterType.java new file mode 100644 index 0000000..d83d622 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/egestion/printer/strategy/PayloadPrinterType.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer.strategy; + +import java.util.Arrays; + +public enum PayloadPrinterType { + + NONE_PRINTER("none-printer"), AAI_RESOURCE_GET_ALL_PRINTER("aai-resource-get-all-printer"); + + private final String value; + + PayloadPrinterType(String input) { + this.value = input; + } + + public String getValue() { + return this.value; + } + + @Override + public String toString() { + return this.value; + } + + public static PayloadPrinterType fromString(String text) { + return Arrays.stream(values()).filter(bl -> bl.getValue().equalsIgnoreCase(text)).findFirst().orElse(null); + } +} diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/AAIResourcesUriTemplates.java b/src/main/java/org/onap/aai/cacher/injestion/parser/AAIResourcesUriTemplates.java new file mode 100644 index 0000000..0885851 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/AAIResourcesUriTemplates.java @@ -0,0 +1,208 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser; + +import com.google.gson.JsonObject; +import org.apache.commons.lang3.StringUtils; +import org.onap.aai.cacher.util.AAIConstants; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriTemplate; +import org.springframework.web.util.UriUtils; + +import javax.ws.rs.core.UriBuilder; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.*; + +@Component +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class AAIResourcesUriTemplates { + + private final Map<String, String> typeToUriTemplate; + + public AAIResourcesUriTemplates() throws IOException { + InputStream inputStream = new FileInputStream(AAIConstants.AAI_RESOURCES_URI_TEMPLATES); + Properties prop = new Properties(); + prop.load(inputStream); + + typeToUriTemplate = new HashMap<>(prop.size() + 1); + for (final String type : prop.stringPropertyNames()) { + typeToUriTemplate.put(type, prop.getProperty(type)); + if (!typeToUriTemplate.containsKey("relationship")) { + typeToUriTemplate.put("relationship", "/relationship-list/relationship/{related-link}"); + } + } + } + + /** + * Get templated aai uri segment by type. + * + * @param type + * @return + */ + public String getUriTemplateByType(String type) { + return typeToUriTemplate.get(type); + } + + public Map<String, String> getUriTemplateMappings(String uri, String template) { + + UriTemplate uriTemplate = new UriTemplate(template); + Map<String, String> mappings = uriTemplate.match(uri); + + mappings.replaceAll((k, v) -> this.decodeProp(v)); + + return mappings; + } + + /** + * For a given uri get an ordered list of templates. + * + * @param uri + * @return + */ + public List<String> uriToTemplates(String uri) { + List<String> uriTemplateList = new ArrayList<>(); + String template = ""; + String truncatedUri = uri; + + while (truncatedUri.contains("/")) { + template = this.getMatchingStartingTemplate(truncatedUri).get(); + uriTemplateList.add(template); + int count = StringUtils.countMatches(template, "/"); + if (count < StringUtils.countMatches(truncatedUri, "/")) { + truncatedUri = StringUtils.substring(truncatedUri, + StringUtils.ordinalIndexOf(truncatedUri, "/", count + 1)); + } else { + truncatedUri = ""; + } + } + + return uriTemplateList; + } + + /** + * For a given uri get an ordered list of templates. + * + * @param uri + * @return + */ + public List<String> uriToSegments(String uri) { + List<String> uriList = new ArrayList<>(); + String template = ""; + String truncatedUri = uri; + + while (truncatedUri.contains("/")) { + template = this.getMatchingStartingTemplate(truncatedUri).get(); + int count = StringUtils.countMatches(template, "/"); + int cutIndex = truncatedUri.length(); + if (count != StringUtils.countMatches(truncatedUri, "/")) { + cutIndex = StringUtils.ordinalIndexOf(truncatedUri, "/", count + 1); + } + uriList.add(StringUtils.substring(truncatedUri, 0, cutIndex)); + truncatedUri = StringUtils.substring(truncatedUri, cutIndex); + } + + return uriList; + } + + /** + * returns the template matching the start of the uri. + * + * @param uri + * @return @see java.util.Optional + */ + public Optional<String> getMatchingStartingTemplate(String uri) { + return typeToUriTemplate.values().stream().filter(s -> uri.startsWith(s.split("/\\{")[0])).findFirst(); + } + + /** + * Given aai type and json object generate the uri for it. + * + * @param type + * @param jo + * @return + */ + public String getUri(String type, JsonObject jo) { + String uriTemplate = getUriTemplateByType(type); + UriBuilder uriBuilder = UriBuilder.fromPath(uriTemplate); + List<String> keys = getUriKeys(uriTemplate); + Map<String, String> mapping = getEncodedMapping(keys, jo); + + return uriBuilder.buildFromEncodedMap(mapping).toString(); + } + + /** + * Get encoded values from json object for each key in keys + * + * @param keys + * @param jo + * @return + */ + private Map<String, String> getEncodedMapping(List<String> keys, JsonObject jo) { + final Map<String, String> mapping = new HashMap<>(); + keys.forEach(key -> mapping.put(key, encodeProp(jo.get(key).getAsString()))); + + return mapping; + } + + /** + * extract uri keys from the templated uri + * + * @param template + * @return + */ + private List<String> getUriKeys(String template) { + + UriTemplate uriTemplate = new UriTemplate(template); + return uriTemplate.getVariableNames(); + } + + /** + * UTF-8 encoding of @param string + * + * @param string string to be encoded + * @return + */ + public String encodeProp(String string) { + try { + return UriUtils.encode(string, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * UTF-8 decoding of @param string + * + * @param string string to be encoded + * @return + */ + public String decodeProp(String string) { + try { + return UriUtils.decode(string, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return ""; + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserFactory.java b/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserFactory.java new file mode 100644 index 0000000..bd36e8f --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserFactory.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser; + +import org.onap.aai.cacher.injestion.parser.strategy.PayloadParserStrategy; +import org.onap.aai.cacher.injestion.parser.strategy.PayloadParserType; + +/** + * Factory to get parser strategy based on parser type. + */ +public interface PayloadParserFactory { + /** + * + * @param ppse payload parser strategy type to use + * @return + */ + PayloadParserStrategy getPayloadParserStrategy(PayloadParserType ppse); +} diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserFactoryConfiguration.java b/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserFactoryConfiguration.java new file mode 100644 index 0000000..28424cb --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserFactoryConfiguration.java @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.config.ServiceLocatorFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class PayloadParserFactoryConfiguration { + + @Bean + public FactoryBean serviceLocatorFactoryBean() { + ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean(); + factoryBean.setServiceLocatorInterface(PayloadParserFactory.class); + return factoryBean; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserService.java b/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserService.java new file mode 100644 index 0000000..1d7b38c --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/PayloadParserService.java @@ -0,0 +1,71 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.onap.aai.cacher.injestion.parser.strategy.PayloadParserStrategy; +import org.onap.aai.cacher.injestion.parser.strategy.PayloadParserType; +import org.onap.aai.cacher.model.CacheEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * Service to be use to interact with parsers. + */ +@Service +public class PayloadParserService { + + private PayloadParserFactory payloadParserFactory; + + @Autowired + public PayloadParserService(PayloadParserFactory payloadParserFactory) { + this.payloadParserFactory = payloadParserFactory; + } + + public List<CacheEntry> doParse(String cacheKey, JsonObject jo, PayloadParserType payloadParserType) { + + PayloadParserStrategy parser = payloadParserFactory.getPayloadParserStrategy(payloadParserType); + return parser.process(cacheKey, jo); + } + + public List<CacheEntry> doParse(String cacheKey, JsonObject jo, String payloadParserTypeStr) { + return doParse(cacheKey, jo, PayloadParserType.fromString(payloadParserTypeStr)); + } + + public List<CacheEntry> doParse(String cacheKey, JsonObject jo) { + return this.doParse(cacheKey, jo, PayloadParserType.NONE); + } + + public List<CacheEntry> doParse(String cacheKey, String jo, PayloadParserType payloadParserType) { + JsonParser jsonParser = new JsonParser(); + return doParse(cacheKey, jsonParser.parse(jo).getAsJsonObject(), payloadParserType); + } + + public List<CacheEntry> doParse(String cacheKey, String jo, String payloadParserTypeStr) { + return doParse(cacheKey, jo, PayloadParserType.fromString(payloadParserTypeStr)); + } + + public List<CacheEntry> doParse(String cacheKey, String jo) { + return this.doParse(cacheKey, jo, PayloadParserType.NONE); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategy.java b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategy.java new file mode 100644 index 0000000..6de0585 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategy.java @@ -0,0 +1,470 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser.strategy; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.apache.commons.lang3.StringUtils; +import org.onap.aai.cacher.injestion.parser.AAIResourcesUriTemplates; +import org.onap.aai.cacher.injestion.parser.PayloadParserService; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.cacher.model.DBAction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * AAI resource get all parser strategy + */ +@Component(value = "aai-resource-dmaap") +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class AAIResourceDmaapParserStrategy implements PayloadParserStrategy { + + protected AAIResourcesUriTemplates aaiResourcesUriTemplates; + + private PayloadParserService payloadParserService; + + private DmaapAction actionType; + + @Autowired + public AAIResourceDmaapParserStrategy(AAIResourcesUriTemplates aaiResourcesUriTemplates, + PayloadParserService payloadParserService) { + this.aaiResourcesUriTemplates = aaiResourcesUriTemplates; + this.payloadParserService = payloadParserService; + } + + /** + * Parses aai resources specific payloads generating the details for caching. + * + * @param originalKey + * @param jsonObject + * @return + */ + @Override + public List<CacheEntry> process(String originalKey, JsonObject jsonObject) { + final List<CacheEntry> cacheEntries = new ArrayList<>(); + + JsonObject header = jsonObject.getAsJsonObject("event-header"); + JsonObject entity = jsonObject.getAsJsonObject("entity"); + String topEntity = header.get("top-entity-type").getAsString(); + + actionType = DmaapAction.valueOf(header.get("action").getAsString()); + boolean isTopLevel = topEntity.equals(header.get("entity-type").getAsString()); + String fullUri = getFullUri(header); + + CacheEntry cacheEntry = generateCacheEntry(entity, actionType, isTopLevel, fullUri); + + cacheEntries.add(cacheEntry); + + // determine relationships on the other end that need to be modified. + MultiValueMap<String, AAIResourceDmaapParserStrategy.AAIRelatedToDetails> relationships; + if (isTopLevel) { + relationships = getFromRelationshipFullUriToRelationshipObj(entity, fullUri); + } else { + relationships = getFromRelationshipFullUriToRelationshipObj(entity, getBaseUri(fullUri)); + } + if (jsonObject.has("existing-obj")) { + adjustRelationshipsBasedOnExisting(jsonObject, fullUri, relationships); + } + + JsonObject relatedToObj; + for (Map.Entry<String, List<AAIResourceDmaapParserStrategy.AAIRelatedToDetails>> relationship : relationships + .entrySet()) { + for (AAIResourceDmaapParserStrategy.AAIRelatedToDetails aaiRelatedToDetails : relationship.getValue()) { + relatedToObj = fullUriToRelationshipObj(relationship.getKey(), aaiRelatedToDetails.getLabel()); + cacheEntries.add(generateCacheEntry(relatedToObj, aaiRelatedToDetails.getActionType(), false, + aaiRelatedToDetails.getFullUri() + "/relationship-list/relationship/" + + aaiResourcesUriTemplates.encodeProp(relationship.getKey()))); + } + } + + return cacheEntries; + } + + private String getBaseUri(String fullUri) { + String uri = getUri(fullUri); + List<AAIUriSegment> uriSegmentList = getAaiUriSegments(uri); + return uriSegmentList.get(0).getSegment(); + } + + protected String getFullUriPrefix(String fullUri) { + return StringUtils.substring(fullUri, 0, StringUtils.ordinalIndexOf(fullUri, "/", 3)); + } + + protected CacheEntry generateCacheEntry(JsonObject entity, DmaapAction actionType, boolean isTopLevel, + String fullUri) { + String uri = getUri(fullUri); + List<AAIUriSegment> uriSegmentList = getAaiUriSegments(uri); + String id = uriSegmentList.get(0).getSegment(); + String collection = uriSegmentList.get(0).getSegmentSingular(); + JsonObject entityBody = getEntityBody(entity, uriSegmentList); + JsonObject findQuery = getFindQuery(uriSegmentList); + JsonObject nestedFindQuery = getNestedFindQuery(uriSegmentList); + String nestedField = getNestedField(uriSegmentList); + JsonObject nestedIdentifier = getNestedIdentifier(uriSegmentList); + DBAction dbAction = getDBAction(actionType); + + return CacheEntry.CacheEntryBuilder.createCacheEntry().inCollection(collection).withDbAction(dbAction) + .withId(id).isNested(!isTopLevel).withPayload(entityBody).withFindQuery(findQuery) + .withNestedFind(nestedFindQuery).withNestedField(nestedField) + .withNestedFieldIdentifierObj(nestedIdentifier).build(); + } + + protected DBAction getDBAction(DmaapAction actionType) { + DBAction dbAction = DBAction.INSERT_REPLACE; + switch (actionType) { + case CREATE: + dbAction = DBAction.INSERT_REPLACE; + break; + case DELETE: + dbAction = DBAction.DELETE; + break; + case UPDATE: + dbAction = DBAction.UPDATE; + break; + } + return dbAction; + } + + protected JsonObject getNestedIdentifier(List<AAIUriSegment> uriSegmentList) { + final JsonObject nestedIdentifier = new JsonObject(); + if (uriSegmentList.size() > 1) { + AAIUriSegment lastSegment = uriSegmentList.get(uriSegmentList.size() - 1); + lastSegment.getSegmentKeyValues().forEach(nestedIdentifier::addProperty); + } + return nestedIdentifier; + } + + protected String getNestedField(List<AAIUriSegment> uriSegmentList) { + StringBuilder nestedField = new StringBuilder(); + + if (uriSegmentList.size() > 1) { + if (uriSegmentList.get(1).getSegmentPlural().isPresent()) { + nestedField.append(uriSegmentList.get(1).getSegmentPlural().get()).append(".") + .append(uriSegmentList.get(1).getSegmentSingular()); + } else { + nestedField.append(uriSegmentList.get(1).getSegmentSingular()); + } + + for (int i = 2; i < uriSegmentList.size(); i++) { + if (uriSegmentList.get(i).getSegmentPlural().isPresent()) { + nestedField.append(".$.").append(uriSegmentList.get(i).getSegmentPlural().get()).append(".") + .append(uriSegmentList.get(i).getSegmentSingular()); + } else { + nestedField.append(".$.").append(uriSegmentList.get(i).getSegmentSingular()); + } + } + } + return nestedField.toString(); + } + + protected JsonObject getNestedFindQuery(List<AAIUriSegment> uriSegmentList) { + return getFindQuery(uriSegmentList, true); + } + + protected JsonObject getFindQuery(List<AAIUriSegment> uriSegmentList) { + return getFindQuery(uriSegmentList, false); + } + + protected JsonObject getFindQuery(List<AAIUriSegment> uriSegmentList, boolean isNested) { + final JsonObject findQuery = new JsonObject(); + if (uriSegmentList.isEmpty()) { + return findQuery; + } + + AAIUriSegment aaiUriSegment = uriSegmentList.get(0); + findQuery.addProperty("_id", aaiUriSegment.getSegment()); + aaiUriSegment.getSegmentKeyValues().forEach(findQuery::addProperty); + + StringBuilder nestedField = new StringBuilder(); + int segmentToProcess = uriSegmentList.size(); + if (!isNested) { + segmentToProcess--; + } + for (int i = 1; i < segmentToProcess; i++) { + aaiUriSegment = uriSegmentList.get(i); + if (nestedField.length() != 0) { + nestedField.append("."); + } + if (aaiUriSegment.getSegmentPlural().isPresent()) { + nestedField.append(aaiUriSegment.getSegmentPlural().get()).append("."); + } + nestedField.append(aaiUriSegment.getSegmentSingular()); + aaiUriSegment.getSegmentKeyValues() + .forEach((k, v) -> findQuery.addProperty(nestedField.toString() + "." + k, v)); + } + return findQuery; + } + + /** + * strips away the parent wrapping from the dmaap events entity payload + * + * @param entity + * @param uriSegmentList + * @return + */ + protected JsonObject getEntityBody(JsonObject entity, List<AAIUriSegment> uriSegmentList) { + + if (uriSegmentList.size() == 1) { + return entity; + } + + JsonObject entityBody = entity.getAsJsonObject(); + + // if processing relationship no need to look for nested obj, entity is the obj + if (!"relationship".equals(uriSegmentList.get(uriSegmentList.size() - 1).getSegmentSingular())) { + for (int i = 1; i < uriSegmentList.size(); i++) { + if (uriSegmentList.get(i).getSegmentPlural().isPresent()) { + entityBody = entityBody.getAsJsonObject(uriSegmentList.get(i).getSegmentPlural().get()) + .getAsJsonArray(uriSegmentList.get(i).getSegmentSingular()).get(0).getAsJsonObject(); + } else { + entityBody = entityBody.getAsJsonArray(uriSegmentList.get(i).getSegmentSingular()).get(0) + .getAsJsonObject(); + } + + } + } + + return entityBody; + + } + + protected List<AAIUriSegment> getAaiUriSegments(String uri) { + List<String> uriSegmentTemplates = aaiResourcesUriTemplates.uriToTemplates(uri); + List<String> uriSegments = aaiResourcesUriTemplates.uriToSegments(uri); + + List<AAIUriSegment> uriSegmentList = new ArrayList<>(uriSegments.size()); + + AAIUriSegment aus; + for (int i = 0; i < uriSegments.size(); i++) { + aus = new AAIUriSegment(uriSegments.get(i), uriSegmentTemplates.get(i)); + aus.setSegmentKeyValues( + aaiResourcesUriTemplates.getUriTemplateMappings(aus.getSegment(), aus.getSegmentTemplate())); + uriSegmentList.add(aus); + } + return uriSegmentList; + } + + /** + * For update events with an existing obj available adjust the cache actions to + * be taken on relationship objects. + * + * @param jsonObject + * @param fullUri + * @param newObjectRelationships + */ + private void adjustRelationshipsBasedOnExisting(JsonObject jsonObject, String fullUri, + MultiValueMap<String, AAIResourceDmaapParserStrategy.AAIRelatedToDetails> newObjectRelationships) { + JsonObject existingObj = jsonObject.getAsJsonObject("existing-obj"); + MultiValueMap<String, AAIResourceDmaapParserStrategy.AAIRelatedToDetails> oldRelationships = getFromRelationshipFullUriToRelationshipObj( + existingObj, fullUri); + oldRelationships.forEach((k, v) -> { + if (newObjectRelationships.containsKey(k)) { + v.forEach(oldA -> { + int found = -1; + for (int i = 0; i < newObjectRelationships.get(k).size(); i++) { + if (newObjectRelationships.get(k).get(i).getFullUri().equals(oldA.getFullUri())) { + found = i; + break; + } + } + if (found != -1) { + newObjectRelationships.get(k).remove(newObjectRelationships.get(k).get(found)); + } else { + oldA.setActionType(DmaapAction.DELETE); + newObjectRelationships.get(k).add(oldA); + } + }); + } else { + v.forEach(aaiRelatedToDetails -> { + aaiRelatedToDetails.setActionType(DmaapAction.DELETE); + newObjectRelationships.add(k, aaiRelatedToDetails); + }); + } + }); + } + + /** + * Given fullUri uri generate an aai relationship obj + * + * @param fullUri + * @return + */ + protected JsonObject fullUriToRelationshipObj(String fullUri, String label) { + final JsonObject relObj = new JsonObject(); + final JsonArray relData = new JsonArray(); + String uri = getUri(fullUri); + List<AAIUriSegment> uriSegmentList = getAaiUriSegments(uri); + + relObj.addProperty("related-to", uriSegmentList.get(uriSegmentList.size() - 1).getSegmentSingular()); + if (label != null) { + relObj.addProperty("relationship-label", label); + } + relObj.addProperty("related-link", fullUri); + + for (AAIUriSegment aaiUriSegment : uriSegmentList) { + aaiUriSegment.getSegmentKeyValues().forEach((k, v) -> { + JsonObject relDataEntry; + relDataEntry = new JsonObject(); + relDataEntry.addProperty("relationship-key", aaiUriSegment.getSegmentSingular() + "." + k); + relDataEntry.addProperty("relationship-value", v); + relData.add(relDataEntry); + }); + } + relObj.add("relationship-data", relData); + + return relObj; + } + + /** + * + * @param entity + * @param fullUri + * @return + */ + protected MultiValueMap<String, AAIResourceDmaapParserStrategy.AAIRelatedToDetails> getFromRelationshipFullUriToRelationshipObj( + JsonObject entity, String fullUri) { + final MultiValueMap<String, AAIResourceDmaapParserStrategy.AAIRelatedToDetails> relationshipMapping = new LinkedMultiValueMap<>(); + for (Map.Entry<String, JsonElement> e : entity.entrySet()) { + if (e.getKey().equals("relationship-list") && e.getValue().isJsonObject()) { + JsonArray relationships = e.getValue().getAsJsonObject().getAsJsonArray("relationship"); + for (JsonElement relationship : relationships) { + relationshipMapping.add(fullUri, new AAIResourceDmaapParserStrategy.AAIRelatedToDetails( + relationship.getAsJsonObject().get("related-link").getAsString(), + relationship.getAsJsonObject().get("relationship-label").getAsString(), actionType)); + } + } else if (e.getValue().isJsonObject() && e.getValue().getAsJsonObject().entrySet().size() == 1) { + Map.Entry<String, JsonElement> entry = e.getValue().getAsJsonObject().entrySet().iterator().next(); + if (entry.getValue().isJsonArray()) { + String type = entry.getKey(); + JsonArray children = entry.getValue().getAsJsonArray(); + for (JsonElement child : children) { + relationshipMapping.putAll(getFromRelationshipFullUriToRelationshipObj(child.getAsJsonObject(), + fullUri + aaiResourcesUriTemplates.getUri(type, child.getAsJsonObject()))); + } + } + } + } + return relationshipMapping; + } + + protected String getUri(String fullUri) { + return fullUri.replaceAll("/aai/v\\d+", ""); + } + + protected String getFullUri(JsonObject header) { + return header.get("entity-link").getAsString(); + } + + protected enum DmaapAction { + DELETE, UPDATE, CREATE + } + + class AAIUriSegment { + + private String segment; + private String segmentTemplate; + private Optional<String> segmentPlural = Optional.empty(); + private String segmentSingular; + private Map<String, String> segmentKeyValues; + + AAIUriSegment(String segment, String template) { + this.segment = segment; + this.segmentTemplate = template; + String[] segmentSplit = segment.split("/"); + String[] templateSplit = template.split("/"); + for (int i = 0; i < templateSplit.length; i++) { + if (templateSplit[i].contains("{")) { + segmentSingular = segmentSplit[i - 1]; + if (!"".equals(segmentSplit[i - 2])) { + segmentPlural = Optional.of(segmentSplit[i - 2]); + } + break; + } + } + } + + String getSegment() { + return segment; + } + + String getSegmentTemplate() { + return segmentTemplate; + } + + Map<String, String> getSegmentKeyValues() { + return segmentKeyValues; + } + + void setSegmentKeyValues(Map<String, String> segmentKeyValues) { + this.segmentKeyValues = segmentKeyValues; + } + + Optional<String> getSegmentPlural() { + return segmentPlural; + } + + String getSegmentSingular() { + return segmentSingular; + } + } + + class AAIRelatedToDetails { + private String fullUri; + private String label; + private DmaapAction actionType; + + public AAIRelatedToDetails(String fullUri, String label, DmaapAction actionType) { + this.fullUri = fullUri; + this.label = label; + this.actionType = actionType; + } + + public String getFullUri() { + return fullUri; + } + + public String getLabel() { + return label; + } + + public DmaapAction getActionType() { + return actionType; + } + + public void setActionType(DmaapAction actionType) { + this.actionType = actionType; + } + + @Override + public String toString() { + return fullUri + " : " + label; + } + } +} diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceGetAllPayloadParserStrategy.java b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceGetAllPayloadParserStrategy.java new file mode 100644 index 0000000..1c2f6cf --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceGetAllPayloadParserStrategy.java @@ -0,0 +1,85 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser.strategy; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.onap.aai.cacher.injestion.parser.AAIResourcesUriTemplates; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.cacher.model.DBAction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * AAI resource get all parser strategy + */ +@Component(value = "aai-resource-get-all") +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class AAIResourceGetAllPayloadParserStrategy implements PayloadParserStrategy { + + AAIResourcesUriTemplates aaiResourcesUriTemplates; + + @Autowired + public AAIResourceGetAllPayloadParserStrategy(AAIResourcesUriTemplates aaiResourcesUriTemplates) { + this.aaiResourcesUriTemplates = aaiResourcesUriTemplates; + } + + /** + * Parses aai resources specific payloads generating the details for . + * + * @param originalKey + * @param jsonObject + * @return + */ + @Override + public List<CacheEntry> process(String originalKey, JsonObject jsonObject) { + final List<CacheEntry> cacheEntries = new ArrayList<>(); + + String type = jsonObject.entrySet().iterator().next().getKey(); + + JsonArray ja = jsonObject.getAsJsonArray(type); + CacheEntry cacheEntry; + String uri; + JsonObject jo; + for (JsonElement jsonElement : ja) { + jo = jsonElement.getAsJsonObject(); + uri = aaiResourcesUriTemplates.getUri(type, jo); + jsonObject.addProperty("_id", uri); + cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry().withId(uri).inCollection(originalKey) + .withFindQuery(getFindQuery(uri)).withPayload(jo).withDbAction(DBAction.INSERT_REPLACE).build(); + cacheEntries.add(cacheEntry); + } + + return cacheEntries; + } + + protected JsonObject getFindQuery(String uri) { + JsonObject jo = new JsonObject(); + jo.addProperty("_id", uri); + return jo; + } + +} diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/NonePayloadParserStrategy.java b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/NonePayloadParserStrategy.java new file mode 100644 index 0000000..9d468b9 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/NonePayloadParserStrategy.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser.strategy; + +import com.google.gson.JsonObject; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.cacher.model.DBAction; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +/** + * Default parser strategy that dont not manipulate the payload. + */ +@Component(value = "none") +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class NonePayloadParserStrategy implements PayloadParserStrategy { + + @Override + public List<CacheEntry> process(String originalKey, JsonObject jsonObject) { + JsonObject find = new JsonObject(); + jsonObject.addProperty("_id", originalKey); + return Collections.singletonList( + CacheEntry.CacheEntryBuilder.createCacheEntry().withId(originalKey).inCollection(originalKey) + .withFindQuery(find).withPayload(jsonObject).withDbAction(DBAction.INSERT_REPLACE).build()); + } + +} diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/PayloadParserStrategy.java b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/PayloadParserStrategy.java new file mode 100644 index 0000000..a8f66b6 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/PayloadParserStrategy.java @@ -0,0 +1,31 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser.strategy; + +import com.google.gson.JsonObject; +import org.onap.aai.cacher.model.CacheEntry; + +import java.util.List; + +public interface PayloadParserStrategy { + + List<CacheEntry> process(String originalKey, JsonObject jsonObject); + +} diff --git a/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/PayloadParserType.java b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/PayloadParserType.java new file mode 100644 index 0000000..b497a8c --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/injestion/parser/strategy/PayloadParserType.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser.strategy; + +import java.util.Arrays; + +public enum PayloadParserType { + + NONE("none"), AAI_RESOURCE_GET_ALL("aai-resource-get-all"), AAI_RESOURCE_DMAAP("aai-resource-dmaap"); + private final String value; + + PayloadParserType(String input) { + this.value = input; + } + + public String getValue() { + return this.value; + } + + @Override + public String toString() { + return this.value; + } + + public static PayloadParserType fromString(String text) { + return Arrays.stream(values()).filter(bl -> bl.getValue().equalsIgnoreCase(text)).findFirst().orElse(null); + } +} diff --git a/src/main/java/org/onap/aai/cacher/model/CacheEntry.java b/src/main/java/org/onap/aai/cacher/model/CacheEntry.java new file mode 100644 index 0000000..ed6715e --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/model/CacheEntry.java @@ -0,0 +1,206 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.model; + +import com.google.gson.JsonObject; + +/** + * Captures the details of a cache entry to be inserted onto the database + */ +public class CacheEntry { + + protected DBAction dbAction; + + protected String id; + protected String collection; + protected JsonObject payload; + protected JsonObject findQuery; + + protected boolean isNested = false; + protected String nestedField; + protected JsonObject nestedFind; + protected JsonObject nestedFieldIdentifierObj; + + private CacheEntry() { + } + + public DBAction getDbAction() { + return dbAction; + } + + public void setDbAction(DBAction dbAction) { + this.dbAction = dbAction; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCollection() { + return collection; + } + + public void setCollection(String collection) { + this.collection = collection; + } + + public JsonObject getPayload() { + return payload; + } + + public void setPayload(JsonObject payload) { + this.payload = payload; + } + + public JsonObject getFindQuery() { + return findQuery; + } + + public void setFindQuery(JsonObject findQuery) { + this.findQuery = findQuery; + } + + public boolean isNested() { + return isNested; + } + + public void setNested(boolean nested) { + isNested = nested; + } + + public String getNestedField() { + return nestedField; + } + + public void setNestedField(String nestedField) { + this.nestedField = nestedField; + } + + public JsonObject getNestedFind() { + return nestedFind; + } + + public void setNestedFind(JsonObject nestedFind) { + this.nestedFind = nestedFind; + } + + public JsonObject getNestedFieldIdentifierObj() { + return nestedFieldIdentifierObj; + } + + public void setNestedFieldIdentifierObj(JsonObject nestedFieldIdentifierObj) { + this.nestedFieldIdentifierObj = nestedFieldIdentifierObj; + } + + public static final class CacheEntryBuilder { + protected DBAction dbAction; + protected String id; + protected String collection; + protected JsonObject payload; + protected JsonObject findQuery; + protected boolean isNested; + protected String nestedField; + protected JsonObject nestedFind; + protected JsonObject nestedFieldIdentifierObj; + + private CacheEntryBuilder() { + } + + public static CacheEntryBuilder createCacheEntry() { + return new CacheEntryBuilder(); + } + + public CacheEntryBuilder deepCopy(CacheEntry cacheEntry) { + dbAction = cacheEntry.getDbAction(); + id = cacheEntry.getId(); + collection = cacheEntry.getCollection(); + payload = cacheEntry.getPayload(); + findQuery = cacheEntry.getFindQuery(); + isNested = cacheEntry.isNested(); + nestedField = cacheEntry.getNestedField(); + nestedFind = cacheEntry.getNestedFind(); + nestedFieldIdentifierObj = cacheEntry.getNestedFieldIdentifierObj(); + return this; + } + + public CacheEntryBuilder withDbAction(DBAction dbAction) { + this.dbAction = dbAction; + return this; + } + + public CacheEntryBuilder withId(String id) { + this.id = id; + return this; + } + + public CacheEntryBuilder inCollection(String collection) { + this.collection = collection; + return this; + } + + public CacheEntryBuilder withPayload(JsonObject payload) { + this.payload = payload; + return this; + } + + public CacheEntryBuilder withFindQuery(JsonObject findQuery) { + this.findQuery = findQuery; + return this; + } + + public CacheEntryBuilder isNested(boolean isNested) { + this.isNested = isNested; + return this; + } + + public CacheEntryBuilder withNestedField(String nestedField) { + this.nestedField = nestedField; + return this; + } + + public CacheEntryBuilder withNestedFind(JsonObject nestedFind) { + this.nestedFind = nestedFind; + return this; + } + + public CacheEntryBuilder withNestedFieldIdentifierObj(JsonObject nestedFieldIdentifierObj) { + this.nestedFieldIdentifierObj = nestedFieldIdentifierObj; + return this; + } + + public CacheEntry build() { + CacheEntry cacheEntry = new CacheEntry(); + cacheEntry.setDbAction(dbAction); + cacheEntry.setId(id); + cacheEntry.setCollection(collection); + cacheEntry.setPayload(payload); + cacheEntry.setFindQuery(findQuery); + cacheEntry.setNestedField(nestedField); + cacheEntry.setNestedFind(nestedFind); + cacheEntry.setNestedFieldIdentifierObj(nestedFieldIdentifierObj); + cacheEntry.isNested = this.isNested; + return cacheEntry; + } + } +} diff --git a/src/main/java/org/onap/aai/cacher/model/CacheKey.java b/src/main/java/org/onap/aai/cacher/model/CacheKey.java new file mode 100644 index 0000000..e87f34a --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/model/CacheKey.java @@ -0,0 +1,220 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.model; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.mongodb.BasicDBObject; + +public class CacheKey { + + public static final String DEFAULT_VALUE = "-1"; + + public String cacheKey = DEFAULT_VALUE; + public String baseUrl = DEFAULT_VALUE; + public String module = DEFAULT_VALUE; + public String URI = DEFAULT_VALUE; + public String timingIndicator = DEFAULT_VALUE; + + public String syncInterval = DEFAULT_VALUE; + public String lastSyncStartTime = DEFAULT_VALUE; + public String lastSyncSuccessTime = DEFAULT_VALUE; + public String lastSyncEndTime = DEFAULT_VALUE; + public String httpBody = DEFAULT_VALUE; + public String httpMethod = DEFAULT_VALUE; + + public String parserStrategy = "none"; + + public CacheKey(String cacheKey) { + this.cacheKey = cacheKey; + } + + public static CacheKey createCacheKeyDefault(JsonObject payload) { + Gson gson = new Gson(); + CacheKey cacheKey = gson.fromJson(payload.toString(), CacheKey.class); + + if (cacheKey.cacheKey == null) { + cacheKey.cacheKey = DEFAULT_VALUE; + if (payload.has("_id")) { + cacheKey.cacheKey = payload.get("_id").getAsString(); + } + } + if (cacheKey.baseUrl == null) { + cacheKey.baseUrl = DEFAULT_VALUE; + } + if (cacheKey.module == null) { + cacheKey.module = DEFAULT_VALUE; + } + if (cacheKey.URI == null) { + cacheKey.URI = DEFAULT_VALUE; + } + if (cacheKey.syncInterval == null) { + cacheKey.syncInterval = DEFAULT_VALUE; + } + if (cacheKey.lastSyncStartTime == null) { + cacheKey.lastSyncStartTime = DEFAULT_VALUE; + } + if (cacheKey.lastSyncSuccessTime == null) { + cacheKey.lastSyncSuccessTime = DEFAULT_VALUE; + } + if (cacheKey.lastSyncEndTime == null) { + cacheKey.lastSyncEndTime = DEFAULT_VALUE; + } + if (cacheKey.httpBody == null) { + cacheKey.httpBody = DEFAULT_VALUE; + } + if (cacheKey.parserStrategy == null) { + cacheKey.parserStrategy = DEFAULT_VALUE; + } + if (cacheKey.timingIndicator == null) { + cacheKey.timingIndicator = DEFAULT_VALUE; + } + if (cacheKey.httpMethod == null) { + cacheKey.httpMethod = DEFAULT_VALUE; + } + return cacheKey; + } + + public static CacheKey fromJson(JsonObject payload) { + CacheKey cacheKey = createCacheKeyDefault(payload); + if (DEFAULT_VALUE.equals(cacheKey.parserStrategy)) { + cacheKey.parserStrategy = "none"; + } + if (DEFAULT_VALUE.equals(cacheKey.timingIndicator)) { + cacheKey.timingIndicator = "firstHit"; + } else if (cacheKey.getTimingIndicator().equals("scheduled") && DEFAULT_VALUE.equals(cacheKey.syncInterval)) { + cacheKey.syncInterval = "1440"; + } + if (DEFAULT_VALUE.equals(cacheKey.httpMethod)) { + cacheKey.httpMethod = "GET"; + } + return cacheKey; + } + + public BasicDBObject toDBObject() { + BasicDBObject document = new BasicDBObject(); + document.put("_id", this.cacheKey); + document.put("baseUrl", this.baseUrl); + document.put("module", this.module); + document.put("URI", this.URI); + document.put("timingIndicator", this.timingIndicator); + document.put("syncInterval", this.syncInterval); + document.put("lastSyncStartTime", this.lastSyncStartTime); + document.put("lastSyncSuccessTime", this.lastSyncSuccessTime); + document.put("lastSyncEndTime", this.lastSyncEndTime); + document.put("httpBody", this.httpBody); + document.put("httpMethod", this.httpMethod); + document.put("parserStrategy", parserStrategy); + return document; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("cacheKey: " + cacheKey + "\n"); + sb.append("Base URL: " + baseUrl + "\n"); + sb.append("Module: " + module + "\n"); + sb.append("URI: " + URI + "\n"); + sb.append("timingIndicator: " + timingIndicator + "\n"); + sb.append("syncInterval: " + syncInterval + "\n"); + sb.append("lastSyncStartTime: " + lastSyncStartTime + "\n"); + sb.append("lastSyncSuccessTime: " + lastSyncSuccessTime + "\n"); + sb.append("lastSyncEndTime: " + lastSyncEndTime + "\n"); + sb.append("httpMethod: " + httpMethod + "\n"); + sb.append("httpBody: " + httpBody + "\n"); + sb.append("parserStrategy: " + parserStrategy + "\n"); + + return sb.toString(); + } + + public String getCacheKey() { + return cacheKey; + } + + public void setCacheKey(String cacheKey) { + this.cacheKey = cacheKey; + } + + public String getBaseUrl() { + return baseUrl; + } + + public String getModule() { + return module; + } + + public String getURI() { + return URI; + } + + public String getTimingIndicator() { + return timingIndicator; + } + + public String getSyncInterval() { + return syncInterval; + } + + public void setSyncInterval(String syncInterval) { + this.syncInterval = syncInterval; + } + + public String getLastSyncStartTime() { + return lastSyncStartTime; + } + + public void setLastSyncStartTime(String ls) { + this.lastSyncStartTime = ls; + } + + public String getLastSyncSuccessTime() { + return lastSyncSuccessTime; + } + + public void setLastSyncSuccessTime(String ls) { + this.lastSyncSuccessTime = ls; + } + + public String getLastSyncEndTime() { + return lastSyncEndTime; + } + + public void setLastSyncEndTime(String le) { + this.lastSyncEndTime = le; + } + + public String getHttpBody() { + return httpBody; + } + + public String getHttpMethod() { + return httpMethod; + } + + public String getParserStrategy() { + return parserStrategy; + } + + public void setParserStrategy(String parserStrategy) { + this.parserStrategy = parserStrategy; + } + +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/model/DBAction.java b/src/main/java/org/onap/aai/cacher/model/DBAction.java new file mode 100644 index 0000000..0d7fbd5 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/model/DBAction.java @@ -0,0 +1,24 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.model; + +public enum DBAction { + DELETE, INSERT_REPLACE, UPDATE +} diff --git a/src/main/java/org/onap/aai/cacher/service/AuthorizationService.java b/src/main/java/org/onap/aai/cacher/service/AuthorizationService.java new file mode 100644 index 0000000..369503a --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/AuthorizationService.java @@ -0,0 +1,109 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.eclipse.jetty.util.security.Password; +import org.onap.aai.cacher.Profiles; +import org.onap.aai.util.AAIConstants; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +@Profile(Profiles.ONE_WAY_SSL) +@Service +public class AuthorizationService { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(AuthorizationService.class); + + private final Map<String, String> authorizedUsers = new HashMap<>(); + + private static final Base64.Encoder ENCODER = Base64.getEncoder(); + + @PostConstruct + public void init(){ + + String basicAuthFile = getBasicAuthFilePath(); + + try(Stream<String> stream = Files.lines(Paths.get(basicAuthFile))){ + stream.filter(line -> !line.startsWith("#")).forEach(str -> { + byte [] bytes = null; + + String usernamePassword = null; + String accessType = null; + + try { + String [] userAccessType = str.split(","); + + if(userAccessType == null || userAccessType.length != 2){ + throw new RuntimeException("Please check the realm.properties file as it is not conforming to the basic auth"); + } + + usernamePassword = userAccessType[0]; + accessType = userAccessType[1]; + + String[] usernamePasswordArray = usernamePassword.split(":"); + + if(usernamePasswordArray == null || usernamePasswordArray.length != 3){ + throw new RuntimeException("Not a valid entry for the realm.properties entry: " + usernamePassword); + } + + String username = usernamePasswordArray[0]; + String password = null; + + if(str.contains("OBF:")){ + password = usernamePasswordArray[1] + ":" + usernamePasswordArray[2]; + password = Password.deobfuscate(password); + } + + bytes = ENCODER.encode((username + ":" + password).getBytes("UTF-8")); + + authorizedUsers.put(new String(bytes), accessType); + + } catch (UnsupportedEncodingException e) + { + logger.error("Unable to support the encoding of the file" + basicAuthFile); + } + + authorizedUsers.put(new String(ENCODER.encode(bytes)), accessType); + }); + } catch (IOException e) { + logger.error("IO Exception occurred during the reading of realm.properties", e); + } + } + + public boolean checkIfUserAuthorized(String authorization){ + return authorizedUsers.containsKey(authorization) && "admin".equals(authorizedUsers.get(authorization)); + } + + public String getBasicAuthFilePath(){ + return AAIConstants.AAI_HOME_ETC_AUTH + AAIConstants.AAI_FILESEP + "realm.properties"; + } +} diff --git a/src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java b/src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java new file mode 100644 index 0000000..8b85174 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java @@ -0,0 +1,545 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.helper; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.collect.Lists; +import com.google.gson.*; +import com.mongodb.*; +import org.onap.aai.cacher.common.MongoHelperSingleton; +import org.onap.aai.cacher.egestion.printer.PayloadPrinterService; +import org.onap.aai.cacher.injestion.parser.PayloadParserService; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.cacher.model.CacheKey; +import org.onap.aai.cacher.util.AAIConstants; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Service +public class CacheHelperService { + + private final static EELFLogger EELF_LOGGER = EELFManager.getInstance().getLogger(CacheHelperService.class); + private Gson gson = new GsonBuilder().create(); + + @Autowired + private MongoHelperSingleton mongoHelper; + + @Autowired + private RestClientHelperService rchs; + + @Autowired + private PayloadParserService payloadParserService; + + @Autowired + private PayloadPrinterService payloadPrinterService; + + public void setMongoHelper(MongoHelperSingleton mongoHelper) { + this.mongoHelper = mongoHelper; + } + + public void setRchs(RestClientHelperService rchs) { + this.rchs = rchs; + } + + public void setPayloadParserService(PayloadParserService payloadParserService) { + this.payloadParserService = payloadParserService; + } + + public void setPayloadPrinterService(PayloadPrinterService payloadPrinterService) { + this.payloadPrinterService = payloadPrinterService; + } + + public CacheKey retrieveCacheKeyObject(CacheKey ck) { + String ckString = retrieveCollectionString(ck, AAIConstants.COLLECTION_CACHEKEY); + if (ckString.equals("")) { + EELF_LOGGER.error("Could not retrieve cache key"); + return null; + } + JsonParser parser = new JsonParser(); + JsonObject ckJson = (JsonObject) parser.parse(ckString); + return CacheKey.fromJson(ckJson); + } + + public String retrieveCollectionString(CacheKey ck, String collectionName) { + StringBuilder result = new StringBuilder(""); + try { + DBCollection collection = mongoHelper.getDb().getCollection(collectionName); + BasicDBObject whereQuery = new BasicDBObject(); + whereQuery.put("_id", ck.getCacheKey()); + DBCursor cursor = collection.find(whereQuery); + while (cursor.hasNext()) { + result.append(cursor.next()); + } + } catch (Exception e) { + e.printStackTrace(); + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + } + return result.toString(); + } + + public boolean isCollectionPresent(String collectionName) { + if (collectionName != null && !collectionName.isEmpty()) { + try { + DBCollection collection = mongoHelper.getDb().getCollection(collectionName); + DBCursor cursor = collection.find(); + if (cursor.count() > 0) { + return true; + } + } catch (Exception e) { + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + } + } + return false; + } + + public String retrieveCollectionString(CacheKey ck) { + JsonArray jsonArray = new JsonArray(); + try { + DBCollection collection = mongoHelper.getDb().getCollection(ck.getCacheKey()); + DBCursor cursor = collection.find(); + if (cursor.count() > 0) { + while (cursor.hasNext()) { + // remove "_id" property from cache response + JsonParser parser = new JsonParser(); + JsonObject jsonObj = (JsonObject) parser.parse(cursor.next().toString()); + jsonObj.remove("_id"); + jsonArray.add(jsonObj); + } + } + } catch (Exception e) { + e.printStackTrace(); + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + } + JsonObject jsonObject = payloadPrinterService.createJson(ck.getCacheKey(), jsonArray, ck.getParserStrategy()); + if (jsonObject != null) { + return jsonObject.toString(); + } + return ""; + } + + public boolean isKeyPresent(CacheKey ck, String collectionName) { + return !retrieveCollectionString(ck, collectionName).equals(""); + } + + public boolean isCurrentlyRunning(CacheKey ck) { + CacheKey ckPopulated = retrieveCacheKeyObject(ck); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ"); + Long syncStartTimeInMillis = -1L; + Long syncLastEndInMillis = -1L; + if (ckPopulated != null && !ckPopulated.getLastSyncStartTime().equals("-1")) { + try { + syncStartTimeInMillis = sdf.parse(ckPopulated.getLastSyncStartTime()).getTime(); + } catch (Exception e) { + // TODO handle exceptions + } + } + if (ckPopulated != null && !ckPopulated.getLastSyncEndTime().equals("-1")) { + try { + syncLastEndInMillis = sdf.parse(ckPopulated.getLastSyncEndTime()).getTime(); + } catch (Exception e) { + // TODO handle exceptions + } + } + return ckPopulated != null && syncLastEndInMillis < syncStartTimeInMillis; + } + + public Response getData(CacheKey ck) { + if (ck == null) { + AAIException aaiException = new AAIException("AAI_3014", "Cache key provided does not exist"); + return buildExceptionResponse(aaiException); + } else if (isCurrentlyRunning(ck)) { + AAIException aaiException = new AAIException("AAI_4000", "Sync is currently running from another process."); + return buildExceptionResponse(aaiException); + } else if (isKeyPresent(ck, AAIConstants.COLLECTION_CACHEKEY)) { + if (isCollectionPresent(ck.getCacheKey())) { + return retrieveCollectionByKey(ck); + } else { + ResponseEntity resp = rchs.triggerRestCall(ck); + if (!resp.getStatusCode().is2xxSuccessful()) { + // TODO log/return accordingly + } + Response response = populateCache(ck, (String) resp.getBody()); + if (response.getStatus() == 201) { + return retrieveCollectionByKey(ck); + } else { + AAIException aaiException = new AAIException("AAI_5105"); + return buildExceptionResponse(aaiException); + } + } + } else { + AAIException aaiException = new AAIException("AAI_3014", "Cache key provided does not exist"); + return buildExceptionResponse(aaiException); + } + } + + public Response forceSync(CacheKey ck) { + if (isCurrentlyRunning(ck)) { + AAIException aaiException = new AAIException("AAI_4000", "Sync is currently running from another process."); + return buildExceptionResponse(aaiException); + } else if (isKeyPresent(ck, AAIConstants.COLLECTION_CACHEKEY)) { + // populate cache and return status on sync + ResponseEntity resp = rchs.triggerRestCall(ck); + if (!resp.getStatusCode().is2xxSuccessful()) { + // TODO unsure if this is correct behavior + return Response.noContent().build(); + } + return populateCache(ck, (String) resp.getBody()); + } else { + AAIException aaiException = new AAIException("AAI_3014", "Cache key provided does not exist"); + return buildExceptionResponse(aaiException); + } + } + + public Response retrieveCollectionByKey(CacheKey ck, String collection) { + Status status = Status.OK; + String result = ""; + try { + result = this.retrieveCollectionString(ck, collection); + + if (result.equals("")) { + status = Status.NOT_FOUND; + EELF_LOGGER.error("Cannot not found the cache key from mongodb"); + } + return this.buildResponse(status, result); + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000", e); + return buildExceptionResponse(aaiException); + + } + } + + public Response retrieveCollectionByKey(CacheKey ck) { + Status status = Status.OK; + String result = ""; + try { + result = this.retrieveCollectionString(ck); + if (result.equals("")) { + status = Status.NOT_FOUND; + EELF_LOGGER.error("Cannot not found the cache key from mongodb"); + } + return this.buildResponse(status, result); + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000", e); + return buildExceptionResponse(aaiException); + + } + } + + public boolean addCacheKey(CacheKey ck) { + return mongoHelper.addToMongo(AAIConstants.COLLECTION_CACHEKEY, ck.toDBObject()); + } + + public Response getAllKeys() { + Status status = Status.OK; + StringBuilder result = new StringBuilder(); + try { + DBCollection collection = mongoHelper.getDb().getCollection(AAIConstants.COLLECTION_CACHEKEY); + DBCursor cursor = collection.find(); + if (cursor.count() > 1) { + result.append("["); + while (cursor.hasNext()) { + result.append(cursor.next()); + if (cursor.numSeen() != cursor.count()) { + result.append(","); + } + } + result.append("]"); + + } else if (cursor.count() == 1) { + while (cursor.hasNext()) { + result.append(cursor.next()); + } + } else { + status = Status.NOT_FOUND; + } + return buildResponse(status, result.toString()); + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000", e); + return buildExceptionResponse(aaiException); + } + } + + public Response updateCacheKey(CacheKey ck) { + DBCollection collection = mongoHelper.getDb().getCollection(AAIConstants.COLLECTION_CACHEKEY); + Status status; + + BasicDBObject updateFields = new BasicDBObject(); + + for (Field field : ck.getClass().getDeclaredFields()) { + try { + String name = field.getName(); + Object value = field.get(ck); + if (!name.equals(AAIConstants.COLLECTION_CACHEKEY) && !value.equals("-1")) { + updateFields.append(name, value); + } + } catch (Exception e) { + EELF_LOGGER.warn("Could not retrieve updatable field from the class", e); + } + } + + BasicDBObject setQuery = new BasicDBObject(); + setQuery.append("$set", updateFields); + + BasicDBObject searchQuery = new BasicDBObject("_id", ck.getCacheKey()); + try { + WriteResult result = collection.update(searchQuery, setQuery); + if (result.getN() > 0) { + status = Status.OK; + } else { + // TODO set proper status for no results updated meaning it didn't find the key + status = Status.NOT_FOUND; + } + return buildResponse(status, "{}"); + } catch (MongoException ex) { + AAIException aaiException = new AAIException("AAI_5105", ex); + return buildExceptionResponse(aaiException); + } + } + + public boolean bulkAddCacheKeys(List<CacheKey> ckList) { + try { + List<BasicDBObject> documents = new ArrayList<BasicDBObject>(); + for (CacheKey ck : ckList) { + documents.add(ck.toDBObject()); + } + return mongoHelper.addToMongo(AAIConstants.COLLECTION_CACHEKEY, documents); + } catch (Exception e) { + AAIException aaiException = new AAIException("AAI_4000", e); + ErrorLogHelper.logException(aaiException); + return false; + } + } + + public Response deleteCacheKeyAndAssociatedCache(String id) { + String cacheDelete = deleteFromCollection(null, id); + dropCollection(id); + String cacheKeyDelete = deleteFromCollection(id, AAIConstants.COLLECTION_CACHEKEY); + Status status; + if (cacheKeyDelete.equals("DELETED") && (cacheDelete.equals("DELETED") || cacheDelete.equals("NOT_FOUND"))) { + status = Status.NO_CONTENT; + return buildResponse(status, "{}"); + } else if (cacheKeyDelete.equals("NOT_FOUND")) { + status = Status.NOT_FOUND; + return buildResponse(status, "{}"); + } else { + AAIException aaiException = new AAIException("AAI_5105"); + return buildExceptionResponse(aaiException); + } + } + + public Response deleteCache(String id, String collection) { + String cacheDelete = deleteFromCollection(id, collection); + Status status; + if (cacheDelete.equals("DELETED")) { + status = Status.NO_CONTENT; + return buildResponse(status, "{}"); + } else if (cacheDelete.equals("NOT_FOUND")) { + status = Status.NOT_FOUND; + return buildResponse(status, "{}"); + } else { + AAIException aaiException = new AAIException("AAI_5105"); + return buildExceptionResponse(aaiException); + } + } + + public String deleteFromCollection(String id, String collection) { + Map<String, String> whereClause = new HashMap<>(); + if (id != null) { + whereClause.put("_id", id); + } + return mongoHelper.deleteFromMongo(collection, whereClause); + } + + public void dropCollection(String collection) { + mongoHelper.dropCollection(collection); + } + + public Response populateCache(CacheKey ck, String responseBody) { + // Check to see if the cache key object is fully populated or an empty + // identifier object + // if it's an empty identifier object pull the entire object + if (ck.getBaseUrl().equals("-1")) { + ck = retrieveCacheKeyObject(ck); + } + DateFormat formatter = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ"); + + List<CacheEntry> cacheEntries = payloadParserService.doParse(ck.getCacheKey(), responseBody, + ck.getParserStrategy()); + for (CacheEntry cacheEntry : cacheEntries) { + boolean success = false; + + switch (cacheEntry.getDbAction()) { + case DELETE: + success = mongoHelper.delete(cacheEntry); + break; + case UPDATE: + success = mongoHelper.insertReplace(cacheEntry); + break; + case INSERT_REPLACE: + success = mongoHelper.insertReplace(cacheEntry); + break; + } + + if (!success) { + ck.setLastSyncEndTime(formatter.format(System.currentTimeMillis())); + updateCacheKey(ck); + AAIException aaiException = new AAIException("AAI_4000", "Unable to populate the cache"); + return buildExceptionResponse(aaiException); + } + } + ck.setLastSyncSuccessTime(formatter.format(System.currentTimeMillis())); + ck.setLastSyncEndTime(formatter.format(System.currentTimeMillis())); + updateCacheKey(ck); + return buildResponse(Status.CREATED, "{}"); + } + + public Response buildResponse(Status status, String result) { + return Response.status(status).type(MediaType.APPLICATION_JSON).entity(result).build(); + } + + public Response buildValidationResponse(List<String> issues) { + AAIException aaiException = new AAIException("AAI_3014"); + ArrayList<String> templateVars = new ArrayList<>(); + + if (templateVars.isEmpty()) { + templateVars.add(issues.toString()); + } + ErrorLogHelper.logException(aaiException); + return Response.status(aaiException.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging( + Lists.newArrayList(MediaType.APPLICATION_JSON_TYPE), aaiException, templateVars)) + .build(); + } + + public Response buildExceptionResponse(AAIException aaiException) { + ErrorLogHelper.logException(aaiException); + return Response.status(aaiException.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging( + Lists.newArrayList(MediaType.APPLICATION_JSON_TYPE), aaiException, new ArrayList<>())) + .build(); + } + + public List<CacheKey> getScheduledCaches() { + List<CacheKey> cks = new ArrayList<>(); + EELF_LOGGER.info("Retrieving scheduled cache keys"); + DBCollection collection = mongoHelper.getDb().getCollection(AAIConstants.COLLECTION_CACHEKEY); + BasicDBObject whereQuery = new BasicDBObject(); + whereQuery.put("timingIndicator", "scheduled"); + DBCursor cursor = collection.find(whereQuery); + while (cursor.hasNext()) { + JsonObject ckJson = (JsonObject) new JsonParser().parse((cursor.next().toString())); + CacheKey ck = CacheKey.fromJson(ckJson); + cks.add(ck); + } + return cks; + } + + public void checkAndInitTasks() { + List<CacheKey> ckList = this.getScheduledCaches(); + int numOfThread = 10; + ExecutorService taskExecutor = Executors.newFixedThreadPool(numOfThread); + try { + List<Callable<Void>> tasks = new ArrayList<>(); + for (CacheKey ck : ckList) { + + boolean shouldTrigger = isShouldTrigger(ck); + + if (shouldTrigger) { + Callable<Void> task = new Callable<Void>() { + @Override + public Void call() throws Exception { + long startTimeV = System.currentTimeMillis(); + ResponseEntity respEntity = rchs.triggerRestCall(ck); + if (respEntity.getStatusCode().is2xxSuccessful()) { + populateCache(ck, (String) respEntity.getBody()); + long endTimeV = System.currentTimeMillis(); + EELF_LOGGER.info("Elapsed time in seconds: " + (endTimeV - startTimeV) / 1000); + } else { + // TODO: cache update failed + } + return null; + } + }; + if (task != null) { + tasks.add(task); + } + } + } + if (!tasks.isEmpty()) { + taskExecutor.invokeAll(tasks); + } + } catch (Exception e) { + e.printStackTrace(); + // TODO throw exception + } finally { + taskExecutor.shutdown(); + } + } + + protected boolean isShouldTrigger(CacheKey ck) { + + // convert minutes to milliseconds for the interval + int interval = Integer.parseInt(ck.getSyncInterval()) * 60000; + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ"); + long syncStartTimeInMillis = Integer.MAX_VALUE; + long syncLastEndInMillis = Integer.MIN_VALUE; + + if ("-1".equals(ck.getLastSyncStartTime())) { + return true; + } else { + try { + syncStartTimeInMillis = sdf.parse(ck.getLastSyncStartTime()).getTime(); + } catch (Exception e) { + e.printStackTrace(); + // TODO handle exceptions + } + } + + if (!"-1".equals(ck.getLastSyncEndTime())) { + try { + syncLastEndInMillis = sdf.parse(ck.getLastSyncEndTime()).getTime(); + } catch (Exception e) { + e.printStackTrace(); + // TODO handle exceptions + } + } + + return ((System.currentTimeMillis() - syncStartTimeInMillis) > interval) + && (syncStartTimeInMillis < syncLastEndInMillis); + } +} diff --git a/src/main/java/org/onap/aai/cacher/service/helper/RestClientHelperService.java b/src/main/java/org/onap/aai/cacher/service/helper/RestClientHelperService.java new file mode 100644 index 0000000..b72101f --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/helper/RestClientHelperService.java @@ -0,0 +1,76 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.helper; + +import org.onap.aai.cacher.model.CacheKey; +import org.onap.aai.cacher.util.RestClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +@Component +public class RestClientHelperService { + + @Autowired + CacheHelperService chs; + + private RestClient restClient = getRestClient(); + + public RestClient getRestClient() { + try { + return new RestClient(); + } catch (Exception e) { + // TODO handle exceptions + return null; + } + } + + /** + * Given a cacheKey trigger its corresponding rest call + * + * @param ck + * @return ResponseEntity to process + */ + public ResponseEntity triggerRestCall(CacheKey ck) { + // populated cacheKey with mongo variables + CacheKey ckPopulated = chs.retrieveCacheKeyObject(ck); + ResponseEntity resp = null; + // Check to see if the cache key object is fully populated or an empty + // identifier object + // if it's an empty identifier object pull the entire object + if ("-1".equals(ck.getBaseUrl())) { + ck = chs.retrieveCacheKeyObject(ck); + } + DateFormat formatter = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ"); + String dateFormatted = formatter.format(System.currentTimeMillis()); + ck.setLastSyncStartTime(dateFormatted); + chs.updateCacheKey(ck); + try { + resp = this.restClient.get(ckPopulated.getBaseUrl(), ckPopulated.getModule(), ckPopulated.getURI(), + "AAI-CACHER"); + } catch (Exception e) { + // TODO log an exception + } + return resp; + } +} diff --git a/src/main/java/org/onap/aai/cacher/service/rest/CacheInteractionService.java b/src/main/java/org/onap/aai/cacher/service/rest/CacheInteractionService.java new file mode 100644 index 0000000..57bebdd --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/rest/CacheInteractionService.java @@ -0,0 +1,88 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.rest; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonParser; +import org.onap.aai.cacher.model.CacheKey; +import org.onap.aai.cacher.service.helper.CacheHelperService; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Path("/cache/v1") +@Produces({ MediaType.APPLICATION_JSON }) +public class CacheInteractionService { + + private final static EELFLogger EELF_LOGGER = EELFManager.getInstance().getLogger(CacheKeyService.class); + + @Autowired + protected CacheHelperService chs; + + /** + * Delete the associated cache and handle responses + * + * @param payload, requires the cache key to delete the cache + */ + @DELETE + @Path("/delete") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response executeDelete(String payload) { + CacheKey ck = CacheKey.fromJson(new JsonParser().parse(payload).getAsJsonObject()); + Response resp = chs.deleteCache(null, ck.getCacheKey()); + chs.dropCollection(ck.getCacheKey()); + return resp; + } + + /** + * Sync the cache from the provided cache key and handle responses + * + * @param payload, needs the cache key in the request payload to force sync the + * cache + */ + @PUT + @Path("/sync") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response executeSync(String payload) { + CacheKey ck = CacheKey.fromJson(new JsonParser().parse(payload).getAsJsonObject()); + return chs.forceSync(ck); + } + + /** + * Execute to build and return the payload for the provided cache key + * + * @param cacheKey, needs the cacheKey to know which response payload to build + * and return + */ + @GET + @Path("/get") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response executeGetSingle(@DefaultValue("-1") @QueryParam("cacheKey") String cacheKey) { + CacheKey ck = new CacheKey(cacheKey); + ck = chs.retrieveCacheKeyObject(ck); + return chs.getData(ck); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/service/rest/CacheKeyService.java b/src/main/java/org/onap/aai/cacher/service/rest/CacheKeyService.java new file mode 100644 index 0000000..962be77 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/rest/CacheKeyService.java @@ -0,0 +1,200 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.rest; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.onap.aai.cacher.model.CacheKey; +import org.onap.aai.cacher.service.helper.CacheHelperService; +import org.onap.aai.cacher.service.rest.util.CacheKeyRequestValidation; +import org.onap.aai.cacher.service.rest.util.CacheKeyRequestValidationType; +import org.onap.aai.cacher.util.AAIConstants; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import java.util.List; + +@Path("/cacheKey/v1") +@Produces({ MediaType.APPLICATION_JSON }) +public class CacheKeyService { + private final static EELFLogger EELF_LOGGER = EELFManager.getInstance().getLogger(CacheKeyService.class); + + @Autowired + protected CacheHelperService chs; + + /** + * Store the cache key to Mongodb + * + * @param payload, the json payload needed to populate the cacheKey object and + * add to the database + */ + @PUT + @Path("/add") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response executeAdd(String payload) { + EELF_LOGGER.info("Got the request to add cache key to mongodb"); + CacheKeyRequestValidation ckrv = new CacheKeyRequestValidation(CacheKeyRequestValidationType.ADD); + JsonObject input = convertStringToJSON(payload); + List<String> issues = ckrv.validateCacheKeyRequest(input, chs); + Response response; + if (!issues.isEmpty()) { + response = chs.buildValidationResponse(issues); + } else { + CacheKey ck = CacheKey.fromJson(convertStringToJSON(payload)); + boolean addSuccessful = chs.addCacheKey(ck); + // Since we are adding an onInit, we need to populate its cache + if (ck.getTimingIndicator().equals("onInit")) { + chs.forceSync(ck); + } + Status status; + if (addSuccessful) { + status = Status.CREATED; + } else { + EELF_LOGGER.error("Adding of cache key was not successfull"); + status = Status.INTERNAL_SERVER_ERROR; + } + response = Response.status(status).type(MediaType.APPLICATION_JSON).build(); + } + return response; + } + + /** + * Update the stored cache key and handle responses + * + * @param payload, the json payload needed to populate the cacheKey object and + * update the entry in the database + */ + @PUT + @Path("/update") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response executeUpdate(String payload) { + EELF_LOGGER.info("Got the request to update cache key in mongodb"); + CacheKeyRequestValidation ckrv = new CacheKeyRequestValidation(CacheKeyRequestValidationType.UPDATE); + JsonObject input = convertStringToJSON(payload); + List<String> issues = ckrv.validateCacheKeyRequest(input, chs); + Response response; + if (!issues.isEmpty()) { + response = chs.buildValidationResponse(issues); + } else { + CacheKey ck = CacheKey.createCacheKeyDefault(input); + response = chs.updateCacheKey(ck); + } + return response; + } + + /** + * Delete the cache key and associated cache and handle responses + * + * @param payload, the json payload needed to delete the cacheKey entry in the + * database + */ + @DELETE + @Path("/delete") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response executeDelete(String payload) { + EELF_LOGGER.info("Got the request to delete cache key from mongodb"); + CacheKeyRequestValidation ckrv = new CacheKeyRequestValidation(CacheKeyRequestValidationType.DELETE); + JsonObject input = convertStringToJSON(payload); + List<String> issues = ckrv.validateCacheKeyRequest(input, chs); + Response response; + if (!issues.isEmpty()) { + response = chs.buildValidationResponse(issues); + } else { + CacheKey ck = new CacheKey(getValueFromPayload(input, "cacheKey")); + response = chs.deleteCacheKeyAndAssociatedCache(ck.getCacheKey()); + } + return response; + } + + /** + * Get the cache key information given a provided cache key, or if no key is + * provided return all keys + * + * @param cacheKey, the string id to match against _id in mongodb as the unique + * cache key + */ + @GET + @Path("/get") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response executeGet(@DefaultValue("-1") @QueryParam("cacheKey") String cacheKey) { + /* + * Method to get a single cache key entry + */ + EELF_LOGGER.info("Got the request to get cache key from mongodb"); + CacheKey ck; + Response response; + if (cacheKey.equals("-1")) { + response = chs.getAllKeys(); + } else { + ck = new CacheKey(cacheKey); + response = chs.retrieveCollectionByKey(ck, AAIConstants.COLLECTION_CACHEKEY); + } + return response; + } + + /** + * This method accepts a string converts it into a JsonObject + * + * @param payload, the string payload to convert to a JsonObject + */ + public JsonObject convertStringToJSON(String payload) { + JsonParser parser = new JsonParser(); + return (JsonObject) parser.parse(payload); + } + + /** + * This method accepts a string payload and extracts the cacheKey + * + * @param payload, the string payload to convert to a JsonObject + */ + public String getValueFromPayload(String payload, String key) { + JsonObject payloadJSON = convertStringToJSON(payload); + if (payloadJSON.has(key)) { + return ((payloadJSON.get(key)).toString()).replaceAll("\"", ""); + } else { + EELF_LOGGER.error("Could not extract cachekey from the payload"); + return null; + } + } + + /** + * This method accepts a JsonObject input and extracts the cacheKey + * + * @param input, the string payload to convert to a JsonObject + */ + public String getValueFromPayload(JsonObject input, String key) { + if (input.has(key)) { + return ((input.get(key)).toString()).replaceAll("\"", ""); + } else { + EELF_LOGGER.error("Could not extract cachekey from the payload"); + return null; + } + } + +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidation.java b/src/main/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidation.java new file mode 100644 index 0000000..4df1921 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidation.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.rest.util; + +import com.google.gson.JsonObject; +import org.onap.aai.cacher.model.CacheKey; +import org.onap.aai.cacher.service.helper.CacheHelperService; +import org.onap.aai.cacher.util.AAIConstants; + +import java.util.ArrayList; +import java.util.List; + +public class CacheKeyRequestValidation { + private CacheKeyRequestValidationType type; + + public CacheKeyRequestValidation(CacheKeyRequestValidationType type) { + this.type = type; + } + + public List<String> validateCacheKeyRequest(JsonObject input, CacheHelperService chs) { + ArrayList<String> results = new ArrayList<>(); + if (input == null) { + results.add("Unsupported CacheKey request format, empty payload."); + return results; + } + CacheKey cacheKey = CacheKey.fromJson(input); + if ("-1".equals(cacheKey.getCacheKey())) { + results.add("Unsupported CacheKey request format, unspecified cacheKey."); + return results; + } + if (type.equals(CacheKeyRequestValidationType.DELETE)) { + return results; + } + + Boolean keyExists = chs.isKeyPresent(cacheKey, AAIConstants.COLLECTION_CACHEKEY); + if (type.equals(CacheKeyRequestValidationType.ADD)) { + if (keyExists) { + results.add("Invalid request to add cacheKey " + cacheKey.getCacheKey() + ", cacheKey exists."); + } + } else if (type.equals(CacheKeyRequestValidationType.UPDATE)) { + if (!keyExists) { + results.add( + "Invalid request to update cacheKey " + cacheKey.getCacheKey() + ", cacheKey does not exist."); + } + } + return results; + } + +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidationType.java b/src/main/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidationType.java new file mode 100644 index 0000000..932d246 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidationType.java @@ -0,0 +1,26 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.rest.util; + +public enum CacheKeyRequestValidationType { + + ADD, UPDATE, DELETE; + +} diff --git a/src/main/java/org/onap/aai/cacher/service/tasks/ScheduledTaskConfig.java b/src/main/java/org/onap/aai/cacher/service/tasks/ScheduledTaskConfig.java new file mode 100644 index 0000000..2a9a403 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/tasks/ScheduledTaskConfig.java @@ -0,0 +1,74 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.tasks; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.onap.aai.cacher.service.helper.CacheHelperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.config.IntervalTask; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +import java.text.SimpleDateFormat; +import java.util.Date; + +@Configuration +public class ScheduledTaskConfig { + + private final static EELFLogger EELF_LOGGER = EELFManager.getInstance().getLogger(ScheduledTaskConfig.class); + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); + private final static int THREAD_POOL_SIZE = 10; + private final static String THREAD_POOL_PREFIX = "poolScheduler"; + private final static int TASK_INTERVAL_TIME = 30000; + private final static int TASK_DELAY_TIME = 0; + + @Configuration + static class RegisterTaskSchedulerViaSchedulingConfigurer implements SchedulingConfigurer { + + @Autowired + protected CacheHelperService chs; + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + taskRegistrar.setTaskScheduler(poolScheduler()); + taskRegistrar.addFixedRateTask(new IntervalTask(new Runnable() { + @Override + public void run() { + EELF_LOGGER.info( + "Job @ fixed rate " + new Date() + ", Thread name is " + Thread.currentThread().getName()); + chs.checkAndInitTasks(); + } + }, TASK_INTERVAL_TIME, TASK_DELAY_TIME)); + } + + @Bean + public TaskScheduler poolScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setThreadNamePrefix(THREAD_POOL_PREFIX); + scheduler.setPoolSize(THREAD_POOL_SIZE); + return scheduler; + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/service/tasks/ScheduledTasks.java b/src/main/java/org/onap/aai/cacher/service/tasks/ScheduledTasks.java new file mode 100644 index 0000000..78c88c7 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/service/tasks/ScheduledTasks.java @@ -0,0 +1,148 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.tasks; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.onap.aai.cacher.common.CacheKeyConfig; +import org.onap.aai.cacher.dmaap.consumer.AAIDmaapEventProcessor; +import org.onap.aai.cacher.dmaap.consumer.AAIEventConsumer; +import org.onap.aai.cacher.dmaap.consumer.DmaapConsumerSingleton; +import org.onap.aai.cacher.model.CacheKey; +import org.onap.aai.cacher.service.helper.CacheHelperService; +import org.onap.aai.cacher.service.helper.RestClientHelperService; +import org.onap.aai.cacher.util.AAIConstants; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.util.AAIConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +@Component +public class ScheduledTasks { + private final static EELFLogger LOGGER = EELFManager.getInstance().getLogger(ScheduledTasks.class); + private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); + + private int checkInterval = -1; + private boolean cacheLoaded = false; + + @Autowired + AAIDmaapEventProcessor aaiDmaapEventProcessor; + + @Autowired + CacheHelperService chs; + + @Autowired + RestClientHelperService rchs; + + /** + * Starts the aaiDmaapEventConsumer task bean init. Will restart 1 min after the + * previous one ended. + */ + @Scheduled(fixedDelay = 60000, initialDelay = 0) + public void dmaapAAIDmaapEventProcessor() { + try { + dmaapAAIEventProcessorTask(); + } catch (Exception e) { + LOGGER.error("ERROR: Exception in scheduled task [" + e.getMessage() + "]."); + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + } + } + + public void dmaapAAIEventProcessorTask() throws Exception { + String methodName = "dmaapAAIEventProcessorTask()"; + + LOGGER.info("Started fixed rate job dmaapAAIEventProcessor @ " + dateFormat.format(new Date())); + LOGGER.debug("started scheduled task for " + methodName + " checkInterval " + checkInterval); + try { + int delayCheck = Integer.parseInt(AAIConfig.get("aai.cacher.dmaap.consumer.delayCheck", "0")); + if (checkInterval > 0 && checkInterval++ < delayCheck) { + return; + } + checkInterval = 1; + if (AAIConfig.get("aai.cacher.dmaap.consumer.enableEventProcessing").equals("true")) { + LOGGER.info("aai.cacher.dmaap.consumer.enableEventProcessing set to true, starting AAIEventConsumer."); + AAIEventConsumer aec = new AAIEventConsumer("aaiDmaaPEventConsumer.properties", false); + aec.startProcessing(aaiDmaapEventProcessor); + } else { + LOGGER.info( + "aai.cacher.dmaap.consumer.enableEventProcessing set to false, not starting AAIDmaapEventConsumer."); + } + // initialize the cache + if (!cacheLoaded) { + LOGGER.info("Start loading cache @ " + dateFormat.format(new Date())); + init(); + cacheLoaded = true; + } + + } catch (Exception e) { + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + } + LOGGER.info("Completed fixed rate job dmaapAAIEventProcessor @ " + dateFormat.format(new Date())); + } + + public void init() throws IOException { + + Path path = Paths.get(AAIConstants.INITIAL_CACHEKEY_CONFIG_FILENAME); + String cacheKeyConfigJson = new String(Files.readAllBytes(path)); + CacheKeyConfig cacheKeyConfig = new CacheKeyConfig(cacheKeyConfigJson); + List<CacheKey> cacheKeys = cacheKeyConfig.populateCacheKeyList(); + chs.bulkAddCacheKeys(cacheKeys); + + for (CacheKey cacheKey : cacheKeys) { + if ("onInit".equalsIgnoreCase(cacheKey.getTimingIndicator())) { + try { + ResponseEntity respEntity = rchs.triggerRestCall(cacheKey); + if (respEntity.getStatusCode().is2xxSuccessful()) { + Response resp = chs.populateCache(cacheKey, (String) respEntity.getBody()); + if (resp != null) { + if (resp.getStatus() == Response.Status.CREATED.getStatusCode()) { + LOGGER.debug("cacheKey " + cacheKey.getCacheKey() + " loaded"); + } else { + LOGGER.error("unexpected 2xx response status for cacheKey " + cacheKey.getCacheKey() + + " " + resp.getStatusInfo()); + } + } + } else { + LOGGER.error("unexpected response status for cacheKey " + cacheKey.getCacheKey() + " " + + respEntity.getStatusCode()); + } + } catch (Exception e) { + e.printStackTrace(); + LOGGER.error("exception caught for cacheKey " + cacheKey.getCacheKey()); + ErrorLogHelper.logException(new AAIException("AAI_4000", e)); + } + } + } + + DmaapConsumerSingleton.getInstance().setProcessEvents(true); + } +} diff --git a/src/main/java/org/onap/aai/cacher/util/AAIConstants.java b/src/main/java/org/onap/aai/cacher/util/AAIConstants.java new file mode 100644 index 0000000..b830ecb --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/util/AAIConstants.java @@ -0,0 +1,51 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.util; + +public final class AAIConstants { + public static final String COLLECTION_CACHEKEY = "cacheKey"; + + /** Default to unix file separator if system property file.separator is null */ + public static final String FILESEP = (System.getProperty("file.separator") == null) ? "/" + : System.getProperty("file.separator"); + + public static final String AAI_BUNDLECONFIG_NAME = (System.getProperty("BUNDLECONFIG_DIR") == null) ? "resources" + : System.getProperty("BUNDLECONFIG_DIR"); + public static final String AAI_HOME_BUNDLECONFIG = (System.getProperty("AJSC_HOME") == null) + ? FILESEP + "opt" + FILESEP + "app" + FILESEP + "aai" + FILESEP + AAI_BUNDLECONFIG_NAME + : System.getProperty("AJSC_HOME") + FILESEP + AAI_BUNDLECONFIG_NAME; + + public static final String AAI_HOME_ETC = AAI_HOME_BUNDLECONFIG + FILESEP + "etc" + FILESEP; + public static final String AAI_HOME_ETC_APP_PROPERTIES = AAI_HOME_ETC + "appprops" + FILESEP; + public static final String INITIAL_CACHEKEY_CONFIG_FILENAME = AAI_HOME_ETC_APP_PROPERTIES + + "initialcachekeyconfig.json"; + public static final String AAI_RESOURCES_URI_TEMPLATES = AAI_HOME_ETC_APP_PROPERTIES + + "aai-resources-uri-templates.properties"; + public static final String AAI_HOME_ETC_AUTH = AAI_HOME_ETC + "auth" + FILESEP; + + public static final String AAI_TRUSTSTORE_FILENAME = "aai.truststore.filename"; + public static final String AAI_TRUSTSTORE_PASSWD = "aai.truststore.passwd"; + public static final String AAI_KEYSTORE_FILENAME = "aai.keystore.filename"; + public static final String AAI_KEYSTORE_PASSWD = "aai.keystore.passwd"; + + private AAIConstants() { + // prevent instantiation + } +} diff --git a/src/main/java/org/onap/aai/cacher/util/RestClient.java b/src/main/java/org/onap/aai/cacher/util/RestClient.java new file mode 100644 index 0000000..0caffd3 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/util/RestClient.java @@ -0,0 +1,157 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.util; + +import org.apache.commons.net.util.Base64; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.onap.aai.util.AAIConfig; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.http.*; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.util.ResourceUtils; +import org.springframework.web.client.ResponseErrorHandler; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.SSLContext; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.security.KeyStore; +import java.util.Collections; + +//@Component +public class RestClient { + + private HttpClient restClient = null; + + private Environment environment; + + public RestClient() { + this.restClient = initClient(); + } + + public HttpClient getRestClient() { + return restClient; + } + + /** + * @return initialized rest client + * + */ + private HttpClient initClient() { + HttpClient rc; + + try { + String truststore_path = AAIConstants.AAI_HOME_ETC_AUTH + + AAIConfig.get(AAIConstants.AAI_TRUSTSTORE_FILENAME); + String truststore_password = AAIConfig.get(AAIConstants.AAI_TRUSTSTORE_PASSWD); + SSLContextBuilder sslContextBuilder = SSLContextBuilder.create(); + + SSLContext sslContext = sslContextBuilder + .loadTrustMaterial(ResourceUtils.getFile(truststore_path), truststore_password.toCharArray()) + .build(); + + rc = HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier((s, sslSession) -> true).build(); + } catch (Exception e) { + // TODO Handle exceptions/logging + rc = null; + } + return rc; + } + + private String getAuth(String baseUrl ) { + int startIndex = baseUrl.indexOf("://") + "://".length(); + int ampersandIndex = baseUrl.indexOf('@'); + if ( ampersandIndex >= 0 ) { + return baseUrl.substring(startIndex, ampersandIndex); + } + return null; + } + + public ResponseEntity get(String baseUrl, String module, String restUri, String sourceName) throws Exception { + ResponseEntity responseEntity = null; + try { + + RestTemplate restTemplate = restTemplate(new RestTemplateBuilder()); + String endpoint; + if (!module.equals("-1")) { + endpoint = module + restUri; + } else { + endpoint = restUri; + } + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.add("X-FromAppId", "AAI-CACHER"); + headers.add("X-TransactionId", "JUNIT"); + String auth = getAuth(baseUrl); + String urlUpdate; + if ( auth != null ) { + byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII"))); + headers.add("Authorization", "Basic " + new String(encodedAuth)); + urlUpdate = baseUrl.replaceAll(auth + "@", ""); + } else { + urlUpdate = baseUrl; + } + HttpEntity httpEntity = new HttpEntity(headers); + responseEntity = restTemplate.exchange(urlUpdate + endpoint, HttpMethod.GET, httpEntity, String.class); + } catch (Exception e) { + e.printStackTrace(); + // TODO handle exceptions + } + return responseEntity; + } + + @Bean + RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception { + RestTemplate restTemplate = builder.requestFactory(new HttpComponentsClientHttpRequestFactory(restClient)) + .build(); + + restTemplate.setErrorHandler(new ResponseErrorHandler() { + @Override + public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException { + return clientHttpResponse.getStatusCode() != HttpStatus.OK; + } + + @Override + public void handleError(ClientHttpResponse clientHttpResponse) throws IOException { + // TODO handle the error + } + }); + + return restTemplate; + } + + private KeyStore loadPfx(String file, char[] password) throws Exception { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + File key = ResourceUtils.getFile(file); + try (InputStream in = new FileInputStream(key)) { + keyStore.load(in, password); + } + return keyStore; + } +} diff --git a/src/main/java/org/onap/aai/cacher/web/JerseyConfiguration.java b/src/main/java/org/onap/aai/cacher/web/JerseyConfiguration.java new file mode 100644 index 0000000..6498f2f --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/web/JerseyConfiguration.java @@ -0,0 +1,132 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.web; + +import org.glassfish.jersey.filter.LoggingFilter; +import org.glassfish.jersey.server.ResourceConfig; +import org.onap.aai.cacher.service.rest.CacheInteractionService; +import org.onap.aai.cacher.service.rest.CacheKeyService; +import org.reflections.Reflections; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.annotation.Priority; +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ContainerResponseFilter; + +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +@Component +@ApplicationPath("/aai") +public class JerseyConfiguration extends ResourceConfig { + private static final Logger log = Logger.getLogger(JerseyConfiguration.class.getName()); + + private Environment env; + + @Autowired + public JerseyConfiguration(Environment env) { + this.env = env; + register(CacheKeyService.class); + register(CacheInteractionService.class); + property("jersey.config.servlet.filter.forwardOn404", true); + // Request Filters + registerFiltersForRequests(); + // Response Filters + registerFiltersForResponses(); + + // Following registers the request headers and response headers + // If the LoggingFilter second argument is set to true, it will print response + // value as well + if ("true".equalsIgnoreCase(env.getProperty("aai.request.logging.enabled"))) { + register(new LoggingFilter(log, false)); + } + } + + public void registerFiltersForRequests() { + + // Find all the classes within the interceptors package + Reflections reflections = new Reflections("org.onap.aai.interceptors"); + // Filter them based on the clazz that was passed in + Set<Class<? extends ContainerRequestFilter>> filters = reflections.getSubTypesOf(ContainerRequestFilter.class); + + // Check to ensure that each of the filter has the @Priority annotation and if + // not throw exception + for (Class filterClass : filters) { + if (filterClass.getAnnotation(Priority.class) == null) { + throw new RuntimeException( + "Container filter " + filterClass.getName() + " does not have @Priority annotation"); + } + } + + // Turn the set back into a list + List<Class<? extends ContainerRequestFilter>> filtersList = filters.stream().filter(f -> { + if (f.isAnnotationPresent(Profile.class) && !env.acceptsProfiles(f.getAnnotation(Profile.class).value())) { + return false; + } + return true; + }).collect(Collectors.toList()); + + // Sort them by their priority levels value + filtersList.sort((c1, c2) -> Integer.valueOf(c1.getAnnotation(Priority.class).value()) + .compareTo(c2.getAnnotation(Priority.class).value())); + + // Then register this to the jersey application + filtersList.forEach(this::register); + } + + public void registerFiltersForResponses() { + + // Find all the classes within the interceptors package + Reflections reflections = new Reflections("org.onap.aai.interceptors"); + // Filter them based on the clazz that was passed in + Set<Class<? extends ContainerResponseFilter>> filters = reflections + .getSubTypesOf(ContainerResponseFilter.class); + + // Check to ensure that each of the filter has the @Priority annotation and if + // not throw exception + for (Class filterClass : filters) { + if (filterClass.getAnnotation(Priority.class) == null) { + throw new RuntimeException( + "Container filter " + filterClass.getName() + " does not have @Priority annotation"); + } + } + + // Turn the set back into a list + List<Class<? extends ContainerResponseFilter>> filtersList = filters.stream().filter(f -> { + if (f.isAnnotationPresent(Profile.class) && !env.acceptsProfiles(f.getAnnotation(Profile.class).value())) { + return false; + } + return true; + }).collect(Collectors.toList()); + + // Sort them by their priority levels value + filtersList.sort((c1, c2) -> Integer.valueOf(c1.getAnnotation(Priority.class).value()) + .compareTo(c2.getAnnotation(Priority.class).value())); + + // Then register this to the jersey application + filtersList.forEach(this::register); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/aai/cacher/web/LocalHostAccessLog.java b/src/main/java/org/onap/aai/cacher/web/LocalHostAccessLog.java new file mode 100644 index 0000000..81addb5 --- /dev/null +++ b/src/main/java/org/onap/aai/cacher/web/LocalHostAccessLog.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.web; + +import ch.qos.logback.access.jetty.RequestLogImpl; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.server.handler.RequestLogHandler; +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Arrays; + +@Configuration +public class LocalHostAccessLog { + + @Bean + public EmbeddedServletContainerFactory jettyConfigBean() { + JettyEmbeddedServletContainerFactory jef = new JettyEmbeddedServletContainerFactory(); + jef.addServerCustomizers((JettyServerCustomizer) server -> { + + HandlerCollection handlers = new HandlerCollection(); + + Arrays.stream(server.getHandlers()).forEach(handlers::addHandler); + + RequestLogHandler requestLogHandler = new RequestLogHandler(); + requestLogHandler.setServer(server); + + RequestLogImpl requestLogImpl = new RequestLogImpl(); + requestLogImpl.setResource("/localhost-access-logback.xml"); + requestLogImpl.start(); + + requestLogHandler.setRequestLog(requestLogImpl); + handlers.addHandler(requestLogHandler); + server.setHandler(handlers); + }); + return jef; + } +} diff --git a/src/main/java/org/onap/aai/interceptors/AAIContainerFilter.java b/src/main/java/org/onap/aai/interceptors/AAIContainerFilter.java new file mode 100644 index 0000000..f1198ae --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/AAIContainerFilter.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors; + +import org.onap.aai.util.FormatDate; + +import java.util.UUID; + +public abstract class AAIContainerFilter { + + protected String genDate() { + FormatDate fd = new FormatDate("YYMMdd-HH:mm:ss:SSS"); + return fd.getDateTime(); + } + + protected boolean isValidUUID(String transId) { + try { + UUID.fromString(transId); + } catch (IllegalArgumentException e) { + return false; + } + return true; + } +} diff --git a/src/main/java/org/onap/aai/interceptors/AAIHeaderProperties.java b/src/main/java/org/onap/aai/interceptors/AAIHeaderProperties.java new file mode 100644 index 0000000..65d16e8 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/AAIHeaderProperties.java @@ -0,0 +1,40 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors; + +public final class AAIHeaderProperties { + + private AAIHeaderProperties() { + } + + public static final String REQUEST_CONTEXT = "aai-request-context"; + + public static final String HTTP_METHOD_OVERRIDE = "X-HTTP-Method-Override"; + + public static final String TRANSACTION_ID = "X-TransactionId"; + + public static final String FROM_APP_ID = "X-FromAppId"; + + public static final String AAI_TX_ID = "X-AAI-TXID"; + + public static final String AAI_REQUEST = "X-REQUEST"; + + public static final String AAI_REQUEST_TS = "X-REQUEST-TS"; +} diff --git a/src/main/java/org/onap/aai/interceptors/post/AAIResponseFilterPriority.java b/src/main/java/org/onap/aai/interceptors/post/AAIResponseFilterPriority.java new file mode 100644 index 0000000..ea657bb --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/post/AAIResponseFilterPriority.java @@ -0,0 +1,40 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.post; + +/** + * Response Filter order is done reverse sorted so in the following case the + * first response filter would be HEADER_MANIPULATION, RESPONSE_TRANS_LOGGING, + * RESET_LOGGING_CONTEXT, and INVALID_RESPONSE_STATUS + */ +public final class AAIResponseFilterPriority { + + private AAIResponseFilterPriority() { + } + + public static final int INVALID_RESPONSE_STATUS = 1000; + + public static final int RESET_LOGGING_CONTEXT = 2000; + + public static final int RESPONSE_TRANS_LOGGING = 3000; + + public static final int HEADER_MANIPULATION = 4000; + +} diff --git a/src/main/java/org/onap/aai/interceptors/post/ResponseTransactionLogging.java b/src/main/java/org/onap/aai/interceptors/post/ResponseTransactionLogging.java new file mode 100644 index 0000000..20fe32a --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/post/ResponseTransactionLogging.java @@ -0,0 +1,118 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.post; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.logging.ErrorLogHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import javax.annotation.Priority; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import java.io.IOException; +import java.util.Objects; +import java.util.Optional; + +@Priority(AAIResponseFilterPriority.RESPONSE_TRANS_LOGGING) +public class ResponseTransactionLogging extends AAIContainerFilter implements ContainerResponseFilter { + + private static final EELFLogger TRANSACTION_LOGGER = EELFManager.getInstance() + .getLogger(ResponseTransactionLogging.class); + + @Autowired + private HttpServletResponse httpServletResponse; + + @Autowired + private Environment env; + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + + this.transLogging(requestContext, responseContext); + + } + + private void transLogging(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { + + String logValue = env.getProperty("aai.transaction.logging"); + String getValue = env.getProperty("aai.transaction.logging.get"); + String postValue = env.getProperty("aai.transaction.logging.post"); + + String transId = requestContext.getHeaderString(AAIHeaderProperties.TRANSACTION_ID); + String fromAppId = requestContext.getHeaderString(AAIHeaderProperties.FROM_APP_ID); + String fullUri = requestContext.getUriInfo().getRequestUri().toString(); + String requestTs = (String) requestContext.getProperty(AAIHeaderProperties.AAI_REQUEST_TS); + + String httpMethod = requestContext.getMethod(); + + String status = Integer.toString(responseContext.getStatus()); + + String request = (String) requestContext.getProperty(AAIHeaderProperties.AAI_REQUEST); + String response = this.getResponseString(responseContext); + + if (!Boolean.parseBoolean(logValue)) { + } else if (!Boolean.parseBoolean(getValue) && "GET".equals(httpMethod)) { + } else if (!Boolean.parseBoolean(postValue) && "POST".equals(httpMethod)) { + } else { + + JsonObject logEntry = new JsonObject(); + logEntry.addProperty("transactionId", transId); + logEntry.addProperty("status", status); + logEntry.addProperty("rqstDate", requestTs); + logEntry.addProperty("respDate", this.genDate()); + logEntry.addProperty("sourceId", fromAppId + ":" + transId); + logEntry.addProperty("resourceId", fullUri); + logEntry.addProperty("resourceType", httpMethod); + logEntry.addProperty("rqstBuf", Objects.toString(request, "")); + logEntry.addProperty("respBuf", Objects.toString(response, "")); + + try { + TRANSACTION_LOGGER.debug(logEntry.toString()); + } catch (Exception e) { + ErrorLogHelper.logError("AAI_4000", "Exception writing transaction log."); + } + } + + } + + private String getResponseString(ContainerResponseContext responseContext) { + JsonObject response = new JsonObject(); + response.addProperty("ID", responseContext.getHeaderString(AAIHeaderProperties.AAI_TX_ID)); + response.addProperty("Content-Type", this.httpServletResponse.getContentType()); + response.addProperty("Response-Code", responseContext.getStatus()); + response.addProperty("Headers", responseContext.getHeaders().toString()); + Optional<Object> entityOptional = Optional.ofNullable(responseContext.getEntity()); + if (entityOptional.isPresent()) { + response.addProperty("Entity", entityOptional.get().toString()); + } else { + response.addProperty("Entity", ""); + } + return response.toString(); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java b/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java new file mode 100644 index 0000000..140165b --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.pre; + +public final class AAIRequestFilterPriority { + + private AAIRequestFilterPriority() {} + + public static final int REQUEST_TRANS_LOGGING = 1000; + + public static final int HEADER_VALIDATION = 2000; + + public static final int SET_LOGGING_CONTEXT = 3000; + + public static final int HTTP_HEADER = 4000; + + public static final int AUTHORIZATION = 4500; + + public static final int HEADER_MANIPULATION = 6000; + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java b/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java new file mode 100644 index 0000000..dfc4376 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java @@ -0,0 +1,87 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.pre; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.logging.ErrorLogHelper; + +@PreMatching +@Priority(AAIRequestFilterPriority.HEADER_VALIDATION) +public class HeaderValidation extends AAIContainerFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + Optional<Response> oResp; + + String transId = requestContext.getHeaderString(AAIHeaderProperties.TRANSACTION_ID); + String fromAppId = requestContext.getHeaderString(AAIHeaderProperties.FROM_APP_ID); + + List<MediaType> acceptHeaderValues = requestContext.getAcceptableMediaTypes(); + + oResp = this.validateHeaderValuePresence(fromAppId, "AAI_4009", acceptHeaderValues); + if (oResp.isPresent()) { + requestContext.abortWith(oResp.get()); + return; + } + oResp = this.validateHeaderValuePresence(transId, "AAI_4010", acceptHeaderValues); + if (oResp.isPresent()) { + requestContext.abortWith(oResp.get()); + return; + } + + if (!this.isValidUUID(transId)) { + transId = UUID.randomUUID().toString(); + requestContext.getHeaders().get(AAIHeaderProperties.TRANSACTION_ID).clear(); + requestContext.getHeaders().add(AAIHeaderProperties.TRANSACTION_ID, transId); + } + + } + + private Optional<Response> validateHeaderValuePresence(String value, String errorCode, + List<MediaType> acceptHeaderValues) { + Response response = null; + AAIException aaie; + if (value == null) { + aaie = new AAIException(errorCode); + return Optional.of(Response.status(aaie.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(acceptHeaderValues, aaie, new ArrayList<>())) + .build()); + } + + return Optional.ofNullable(response); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java b/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java new file mode 100644 index 0000000..c627b85 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java @@ -0,0 +1,79 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.pre; + +import org.onap.aai.cacher.Profiles; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.cacher.service.AuthorizationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Profile(Profiles.ONE_WAY_SSL) +@PreMatching +@Priority(AAIRequestFilterPriority.AUTHORIZATION) +public class OneWaySslAuthorization extends AAIContainerFilter implements ContainerRequestFilter { + + @Autowired + private AuthorizationService authorizationService; + + @Override + public void filter(ContainerRequestContext containerRequestContext) throws IOException + { + + String basicAuth = containerRequestContext.getHeaderString("Authorization"); + List<MediaType> acceptHeaderValues = containerRequestContext.getAcceptableMediaTypes(); + + if(basicAuth == null || !basicAuth.startsWith("Basic ")){ + Optional<Response> responseOptional = errorResponse("AAI_3300", acceptHeaderValues); + containerRequestContext.abortWith(responseOptional.get()); + return; + } + + basicAuth = basicAuth.replaceAll("Basic ", ""); + + if(!authorizationService.checkIfUserAuthorized(basicAuth)){ + Optional<Response> responseOptional = errorResponse("AAI_3300", acceptHeaderValues); + containerRequestContext.abortWith(responseOptional.get()); + return; + } + + } + + private Optional<Response> errorResponse(String errorCode, List<MediaType> acceptHeaderValues) { + AAIException aaie = new AAIException(errorCode); + return Optional.of(Response.status(aaie.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(acceptHeaderValues, aaie, new ArrayList<>())) + .build()); + + } +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/RequestHeaderManipulation.java b/src/main/java/org/onap/aai/interceptors/pre/RequestHeaderManipulation.java new file mode 100644 index 0000000..1d9063f --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/RequestHeaderManipulation.java @@ -0,0 +1,60 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.pre; + +import java.io.IOException; +import java.util.Collections; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MultivaluedMap; + +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.springframework.beans.factory.annotation.Autowired; + +@PreMatching +@Priority(AAIRequestFilterPriority.HEADER_MANIPULATION) +public class RequestHeaderManipulation extends AAIContainerFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext requestContext) { + + String uri = requestContext.getUriInfo().getPath(); + this.addRequestContext(uri, requestContext.getHeaders()); + + } + + private void addRequestContext(String uri, MultivaluedMap<String, String> requestHeaders) { + + String rc = ""; + + if (requestHeaders.containsKey(AAIHeaderProperties.REQUEST_CONTEXT)) { + requestHeaders.remove(AAIHeaderProperties.REQUEST_CONTEXT); + } + requestHeaders.put(AAIHeaderProperties.REQUEST_CONTEXT, Collections.singletonList(rc)); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java b/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java new file mode 100644 index 0000000..f9976c2 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java @@ -0,0 +1,131 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.pre; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Random; +import java.util.UUID; +import java.security.SecureRandom; + +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; + +import org.glassfish.jersey.message.internal.ReaderWriter; +import org.glassfish.jersey.server.ContainerException; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.util.AAIConfig; +import org.onap.aai.util.AAIConstants; +import org.onap.aai.util.HbaseSaltPrefixer; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.gson.JsonObject; +import org.springframework.util.StringUtils; + +@PreMatching +@Priority(AAIRequestFilterPriority.REQUEST_TRANS_LOGGING) +public class RequestTransactionLogging extends AAIContainerFilter implements ContainerRequestFilter { + + @Autowired + private HttpServletRequest httpServletRequest; + + private static final String DEFAULT_CONTENT_TYPE = MediaType.APPLICATION_JSON; + private static final String DEFAULT_RESPONSE_TYPE = MediaType.APPLICATION_XML; + + private static final String CONTENT_TYPE = "Content-Type"; + private static final String ACCEPT = "Accept"; + private static final String TEXT_PLAIN = "text/plain"; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + String currentTimeStamp = genDate(); + String fullId = this.getAAITxIdToHeader(currentTimeStamp); + this.addToRequestContext(requestContext, AAIHeaderProperties.AAI_TX_ID, fullId); + this.addToRequestContext(requestContext, AAIHeaderProperties.AAI_REQUEST, this.getRequest(requestContext, fullId)); + this.addToRequestContext(requestContext, AAIHeaderProperties.AAI_REQUEST_TS, currentTimeStamp); + this.addDefaultContentType(requestContext); + } + + private void addToRequestContext(ContainerRequestContext requestContext, String name, String aaiTxIdToHeader) { + requestContext.setProperty(name, aaiTxIdToHeader); + } + + private void addDefaultContentType(ContainerRequestContext requestContext) { + + String contentType = requestContext.getHeaderString(CONTENT_TYPE); + String acceptType = requestContext.getHeaderString(ACCEPT); + + if(contentType == null || contentType.contains(TEXT_PLAIN)){ + requestContext.getHeaders().putSingle(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); + } + + if(StringUtils.isEmpty(acceptType) || acceptType.contains(TEXT_PLAIN)){ + requestContext.getHeaders().putSingle(ACCEPT, DEFAULT_RESPONSE_TYPE); + } + } + + private String getAAITxIdToHeader(String currentTimeStamp) { + String txId = UUID.randomUUID().toString(); + try { + Random rand = new SecureRandom(); + int number = rand.nextInt(99999); + txId = HbaseSaltPrefixer.getInstance().prependSalt(AAIConfig.get(AAIConstants.AAI_NODENAME) + "-" + + currentTimeStamp + "-" + number ); //new Random(System.currentTimeMillis()).nextInt(99999) + } catch (AAIException e) { + } + + return txId; + } + + private String getRequest(ContainerRequestContext requestContext, String fullId) { + + JsonObject request = new JsonObject(); + request.addProperty("ID", fullId); + request.addProperty("Http-Method", requestContext.getMethod()); + request.addProperty(CONTENT_TYPE, httpServletRequest.getContentType()); + request.addProperty("Headers", requestContext.getHeaders().toString()); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + InputStream in = requestContext.getEntityStream(); + + try { + if (in.available() > 0) { + ReaderWriter.writeTo(in, out); + byte[] requestEntity = out.toByteArray(); + request.addProperty("Payload", new String(requestEntity, "UTF-8")); + requestContext.setEntityStream(new ByteArrayInputStream(requestEntity)); + } + } catch (IOException ex) { + throw new ContainerException(ex); + } + + return request.toString(); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java b/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java new file mode 100644 index 0000000..368d071 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java @@ -0,0 +1,70 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.interceptors.pre; + +import java.io.IOException; + +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; + +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.logging.LoggingContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +@PreMatching +@Priority(AAIRequestFilterPriority.SET_LOGGING_CONTEXT) +public class SetLoggingContext extends AAIContainerFilter implements ContainerRequestFilter { + + @Autowired + private Environment environment; + + @Autowired + private HttpServletRequest httpServletRequest; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + String uri = httpServletRequest.getRequestURI(); + String queryString = httpServletRequest.getQueryString(); + + if(queryString != null && !queryString.isEmpty()){ + uri = uri + "?" + queryString; + } + + String httpMethod = requestContext.getMethod(); + String transId = requestContext.getHeaderString(AAIHeaderProperties.TRANSACTION_ID); + String fromAppId = requestContext.getHeaderString(AAIHeaderProperties.FROM_APP_ID); + + LoggingContext.init(); + LoggingContext.requestId(transId); + LoggingContext.partnerName(fromAppId); + LoggingContext.targetEntity(environment.getProperty("spring.application.name")); + LoggingContext.component(fromAppId); + LoggingContext.serviceName(httpMethod + " " + uri); + LoggingContext.targetServiceName(httpMethod + " " + uri); + LoggingContext.statusCode(LoggingContext.StatusCode.COMPLETE); + } + +} diff --git a/src/main/jenkins/Jenkinsfile b/src/main/jenkins/Jenkinsfile new file mode 100644 index 0000000..c74d439 --- /dev/null +++ b/src/main/jenkins/Jenkinsfile @@ -0,0 +1,31 @@ +node ("${BUILD_SLAVE}") { + // get the jenkinsfile root directory + def rootDir = pwd() + + def JAVA_HOME = tool 'jdk180' + env.PATH = "${JAVA_HOME}/bin:${env.PATH}" + sh 'which java' + sh 'java -version' + + env.DOCKER_HOST="tcp://localhost:4243" + + // load external groovy scripts + def build + def checkout + def deploy + dir('tmp') { + git url: "${GIT_URL}", branch: "${GIT_BRANCH}" + checkout = load 'src/main/jenkins/checkout.groovy' + build = load 'src/main/jenkins/build.groovy' + deploy = load 'src/main/jenkins/deploy.groovy' + } + + // check out code from git + checkout.gitCheckout() + + // build the git project + build.buildProject() + + deploy.deployService() + +}
\ No newline at end of file diff --git a/src/main/jenkins/build.groovy b/src/main/jenkins/build.groovy new file mode 100644 index 0000000..3170510 --- /dev/null +++ b/src/main/jenkins/build.groovy @@ -0,0 +1,14 @@ + + +def buildProject() { + stage 'Build Git Project' + wrap([$class: 'ConfigFileBuildWrapper', managedFiles: [[fileId: 'eb0c7cc1-e851-4bc2-9401-2680c225f88c', targetLocation: '', variable: 'MAVEN_SETTINGS']]]) { + mvn '-s $MAVEN_SETTINGS -f pom.xml' +} +} + +def mvn(args) { + sh "${tool 'maven3'}/bin/mvn ${args} ${MAVEN_GOALS}" +} + +return this
\ No newline at end of file diff --git a/src/main/jenkins/checkout.groovy b/src/main/jenkins/checkout.groovy new file mode 100644 index 0000000..ed439ec --- /dev/null +++ b/src/main/jenkins/checkout.groovy @@ -0,0 +1,14 @@ + +def gitCheckout() { + stage 'Checkout GIT' + //different ways to checkout + //checkout from master + //git "url: ${GIT_URL}, branch: ${GIT_BRANCH}" + //checkout from branch hardcoding" + //git branch: 'jenkins_deploy_test', credentialsId: 'b9bbafe5-53ce-4d2c-8b84-09137f75c592', url: 'https://codecloud.web.att.com/scm/st_ocnp/sdk-java-starter.git' + //checkout from branch parameters with credentials + //git branch: "${GIT_BRANCH}", credentialsId: 'b9bbafe5-53ce-4d2c-8b84-09137f75c592', url: "${GIT_URL}" + //checkout from branch parameters with no credentials + git branch: "${GIT_BRANCH}", url: "${GIT_URL}" +} +return this
\ No newline at end of file diff --git a/src/main/jenkins/deploy.groovy b/src/main/jenkins/deploy.groovy new file mode 100644 index 0000000..1a000e3 --- /dev/null +++ b/src/main/jenkins/deploy.groovy @@ -0,0 +1,15 @@ +def deployService(){ + stage 'Deploying Service' + + // get the jenkinsfile root directory + def ROOT_DIR = pwd() + ROOT_DIR = "${ROOT_DIR}"+'/src/main/kubernetes' + echo "ROOTDIR : ${ROOT_DIR}" + sh "/opt/app/kubernetes/v1.3.4/bin/kubectl --kubeconfig=${ROOT_DIR}/kubectl.conf replace --force --cascade -f ${ROOT_DIR}/${artifactId}-svc.yaml" + sh "/opt/app/kubernetes/v1.3.4/bin/kubectl --kubeconfig=${ROOT_DIR}/kubectl.conf replace --force --cascade -f ${ROOT_DIR}/${artifactId}-rc.yaml" +} +return this + + + + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..cd51b92 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,57 @@ +info.build.artifact=@project.artifactId@ +info.build.name=@project.name@ +info.build.description=@project.description@ +info.build.version=@project.version@ + +spring.application.name=aai-cacher +spring.jersey.type=filter +spring.mvc.urls=swagger,docs,prometheus + + +server.contextPath=/ +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration + +spring.profiles.active=production,one-way-ssl + +#The max number of active threads in this pool +server.tomcat.max-threads=200 +#The minimum number of threads always kept alive +server.tomcat.min-Spare-Threads=25 +#The number of milliseconds before an idle thread shutsdown, unless the number of active threads are less or equal to minSpareThreads +server.tomcat.max-idle-time=60000 + + +#Add this properties only if you want to change the URL, AJSC Framework interceptors will intercept +#com.att.ajsc.common.interceptors.PreInterceptor.url=/** +#com.att.ajsc.common.interceptors.PostInterceptor.url=/** + +#Servlet context parameters +server.context_parameters.p-name=value #context parameter with p-name as key and value as value. +kubernetes.namespace=org-onap-aai + +#Dont override +archetype.version=6.3.3.8 +archetype.name=sdk-java-jersey-archetype + +server.local.startpath=src/main/resources/ +server.basic.auth.location=${server.local.startpath}etc/auth/realm.properties + +server.port = 8444 +server.ssl.enabled-protocols=TLSv1.1,TLSv1.2 +server.ssl.key-store=${server.local.startpath}etc/auth/aai_keystore +server.ssl.key-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) +server.ssl.trust-store=${server.local.startpath}etc/auth/aai_keystore +server.ssl.trust-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) +server.ssl.client-auth=want +server.ssl.key-store-type=JKS + +#mongodb configuration values +mongodb.host=localhost +mongodb.dbName=aai +mongodb.port=27017 + +#logging configurations +aai.transaction.logging=true +aai.transaction.logging.get=true +aai.transaction.logging.post=true + diff --git a/src/main/resources/etc/appprops/aai-resources-uri-templates.properties b/src/main/resources/etc/appprops/aai-resources-uri-templates.properties new file mode 100644 index 0000000..44066e1 --- /dev/null +++ b/src/main/resources/etc/appprops/aai-resources-uri-templates.properties @@ -0,0 +1,95 @@ +allotted-resource=/allotted-resources/allotted-resource/{id} +availability-zone=/availability-zones/availability-zone/{availability-zone-name} +class-of-service=/classes-of-service/class-of-service/{cos} +cloud-region=/cloud-infrastructure/cloud-regions/cloud-region/{cloud-owner}/{cloud-region-id} +collection=/network/collections/collection/{collection-id} +complex=/cloud-infrastructure/complexes/complex/{physical-location-id} +configuration=/network/configurations/configuration/{configuration-id} +connector=/business/connectors/connector/{resource-instance-id} +constrained-element-set=/constrained-element-sets/constrained-element-set/{constrained-element-set-uuid} +ctag-assignment=/ctag-assignments/ctag-assignment/{vlan-id-inner} +ctag-pool=/ctag-pools/ctag-pool/{target-pe}/{availability-zone-name} +customer=/business/customers/customer/{global-customer-id} +cvlan-tag-entry=/cvlan-tags/cvlan-tag-entry/{cvlan-tag} +dvs-switch=/dvs-switches/dvs-switch/{switch-name} +element-choice-set=/element-choice-sets/element-choice-set/{element-choice-set-uuid} +entitlement=/entitlements/entitlement/{group-uuid}/{resource-uuid} +evc=/evcs/evc/{evc-id} +flavor=/flavors/flavor/{flavor-id} +forwarder-evc=/forwarder-evcs/forwarder-evc/{forwarder-evc-id} +forwarder=/forwarders/forwarder/{sequence} +forwarding-path=/network/forwarding-paths/forwarding-path/{forwarding-path-id} +generic-vnf=/network/generic-vnfs/generic-vnf/{vnf-id} +group-assignment=/group-assignments/group-assignment/{group-id} +host-route=/host-routes/host-route/{host-route-id} +image=/images/image/{image-id} +instance-group=/network/instance-groups/instance-group/{id} +ipsec-configuration=/network/ipsec-configurations/ipsec-configuration/{ipsec-configuration-id} +l-interface=/l-interfaces/l-interface/{interface-name} +l3-interface-ipv4-address-list=/l3-interface-ipv4-address-list/{l3-interface-ipv4-address} +l3-interface-ipv6-address-list=/l3-interface-ipv6-address-list/{l3-interface-ipv6-address} +l3-network=/network/l3-networks/l3-network/{network-id} +lag-interface=/lag-interfaces/lag-interface/{interface-name} +lag-link=/network/lag-links/lag-link/{link-name} +license=/licenses/license/{group-uuid}/{resource-uuid} +line-of-business=/business/lines-of-business/line-of-business/{line-of-business-name} +logical-link=/network/logical-links/logical-link/{link-name} +metadatum=/metadata/metadatum/{metaname} +model-constraint=/model-constraints/model-constraint/{model-constraint-uuid} +model-element=/model-elements/model-element/{model-element-uuid} +model-ver=/model-vers/model-ver/{model-version-id} +model=/service-design-and-creation/models/model/{model-invariant-id} +multicast-configuration=/network/multicast-configurations/multicast-configuration/{multicast-configuration-id} +named-query-element=/named-query-elements/named-query-element/{named-query-element-uuid} +named-query=/service-design-and-creation/named-queries/named-query/{named-query-uuid} +network-policy=/network/network-policies/network-policy/{network-policy-id} +network-profile=/cloud-infrastructure/network-profiles/network-profile/{nm-profile-name} +newvce=/network/newvces/newvce/{vnf-id2} +nos-server=/nos-servers/nos-server/{nos-server-id} +oam-network=/oam-networks/oam-network/{network-uuid} +operational-environment=/cloud-infrastructure/operational-environments/operational-environment/{operational-environment-id} +overloaded-model=/overloaded-model/{model-invariant-id}/{model-name-version-id} +owning-entity=/business/owning-entities/owning-entity/{owning-entity-id} +p-interface=/p-interfaces/p-interface/{interface-name} +physical-link=/network/physical-links/physical-link/{link-name} +platform=/business/platforms/platform/{platform-name} +pnf=/network/pnfs/pnf/{pnf-name} +port-group=/port-groups/port-group/{interface-id} +project=/business/projects/project/{project-name} +property-constraint=/property-constraints/property-constraint/{property-constraint-uuid} +pserver=/cloud-infrastructure/pservers/pserver/{hostname} +related-lookup=/related-lookups/related-lookup/{related-lookup-uuid} +relationship=/relationship-list/relationship/{related-link} +route-table-reference=/network/route-table-references/route-table-reference/{route-table-reference-id} +route-target=/route-targets/route-target/{global-route-target}/{route-target-role} +routing-instance=/routing-instances/routing-instance/{routing-instance-id} +segmentation-assignment=/segmentation-assignments/segmentation-assignment/{segmentation-id} +service-capability=/service-design-and-creation/service-capabilities/service-capability/{service-type}/{vnf-type} +service-instance=/service-instances/service-instance/{service-instance-id} +service-subscription=/service-subscriptions/service-subscription/{service-type} +service=/service-design-and-creation/services/service/{service-id} +site-pair-set=/network/site-pair-sets/site-pair-set/{site-pair-set-id} +site-pair=/site-pairs/site-pair/{site-pair-id} +snapshot=/snapshots/snapshot/{snapshot-id} +sriov-pf=/sriov-pfs/sriov-pf/{pf-pci-id} +sriov-vf=/sriov-vfs/sriov-vf/{pci-id} +subnet=/subnets/subnet/{subnet-id} +tenant=/tenants/tenant/{tenant-id} +tunnel-xconnect=/tunnel-xconnects/tunnel-xconnect/{id} +vce=/network/vces/vce/{vnf-id} +vf-module=/vf-modules/vf-module/{vf-module-id} +vig-server=/vig-servers/vig-server/{vig-address-type} +vip-ipv4-address-list=/vip-ipv4-address-list/{vip-ipv4-address} +vip-ipv6-address-list=/vip-ipv6-address-list/{vip-ipv6-address} +virtual-data-center=/cloud-infrastructure/virtual-data-centers/virtual-data-center/{vdc-id} +vlan-mapping=/vlan-mappings/vlan-mapping/{vlan-mapping-id} +vlan=/vlans/vlan/{vlan-interface} +vnf-image=/service-design-and-creation/vnf-images/vnf-image/{vnf-image-uuid} +vnf=/vnf/{vnf-id} +vnfc=/network/vnfcs/vnfc/{vnfc-name} +volume-group=/volume-groups/volume-group/{volume-group-id} +volume=/volumes/volume/{volume-id} +vpls-pe=/network/vpls-pes/vpls-pe/{equipment-name} +vpn-binding=/network/vpn-bindings/vpn-binding/{vpn-id} +vserver=/vservers/vserver/{vserver-id} +zone=/network/zones/zone/{zone-id}
\ No newline at end of file diff --git a/src/main/resources/etc/appprops/aaiDmaaPEventConsumer.properties b/src/main/resources/etc/appprops/aaiDmaaPEventConsumer.properties new file mode 100644 index 0000000..398e175 --- /dev/null +++ b/src/main/resources/etc/appprops/aaiDmaaPEventConsumer.properties @@ -0,0 +1,23 @@ +TransportType=TBD +Latitude=TBD +Longitude=TBD + +Version=1.0 +ServiceName=TBD +Environment=TEST +Partner=BOT_R +routeOffer=MR1SBKCD +SubContextPath=/ +Protocol=http +MethodType=GET +username=TBD +password=TBD +contenttype=application/json +host=TBD +topic=AAI-EVENT +group=aaiEventConsumer-dev +id=NA +timeout=15000 +limit=1000 +filter={"event-header.domain":"devINT1"} +sessionstickinessrequired=no
\ No newline at end of file diff --git a/src/main/resources/etc/appprops/aaiconfig.properties b/src/main/resources/etc/appprops/aaiconfig.properties new file mode 100644 index 0000000..0524c13 --- /dev/null +++ b/src/main/resources/etc/appprops/aaiconfig.properties @@ -0,0 +1,5 @@ +aai.truststore.filename=aai_keystore +aai.truststore.passwd.x=OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0 +aai.logging.maxStackTraceEntries=10 +aai.cacher.dmaap.consumer.enableEventProcessing=false +aai.cacher.dmaap.consumer.delayCheck=2 diff --git a/src/main/resources/etc/appprops/error.properties b/src/main/resources/etc/appprops/error.properties new file mode 100644 index 0000000..896df00 --- /dev/null +++ b/src/main/resources/etc/appprops/error.properties @@ -0,0 +1,173 @@ +# Adding comment trying to trigger a build +#------------------------------------------------------------------------------- ---------- +#Key=Disposition:Category:Severity:Error Code:HTTP ResponseCode:RESTError Code:Error Message +#------------------------------------------------------------------------------- ---------- +# testing code, please don't change unless error utility source code changes +AAI_TESTING=5:2:WARN:0000:400:0001:Error code for testing + +# General success +AAI_0000=0:0:INFO:0000:200:0000:Success + +# health check success +AAI_0001=0:0:INFO:0001:200:0001:Success X-FromAppId=%1 X-TransactionId=%2 +AAI_0002=0:0:INFO:0002:200:0001:Successful health check + +# Success with additional info +AAI_0003=0:3:INFO:0003:202:0003:Success with additional info performing %1 on %2. Added %3 with key %4 +AAI_0004=0:3:INFO:0004:202:0003:Added prerequisite object to db + +#--- aairest: 3000-3299 +# svc errors +AAI_3000=5:2:INFO:3000:400:3000:Invalid input performing %1 on %2 +AAI_3001=5:6:INFO:3001:404:3001:Resource not found for %1 using id %2 +AAI_3002=5:1:WARN:3002:400:3002:Error writing output performing %1 on %2 +AAI_3003=5:1:WARN:3003:400:3003:Failed to make edge to missing target node of type %3 with keys %4 performing %1 on %2 +AAI_3005=5:6:WARN:3005:404:3001:Node cannot be directly accessed for read, must be accessed via ancestor(s) +AAI_3006=5:6:WARN:3006:404:3001:Node cannot be directly accessed for write, must be accessed via ancestor(s) +AAI_3007=5:6:INFO:3007:410:3007:This version (%1) of the API is retired, please migrate to %2 +AAI_3008=5:6:WARN:3008:400:3008:URI is not encoded in UTF-8 +AAI_3009=5:6:WARN:3009:400:3002:Malformed URL +AAI_3010=5:6:WARN:3010:400:3002:Cannot write via this URL +AAI_3011=5:6:WARN:3011:400:3000:Unknown XML namespace used in payload +AAI_3012=5:6:WARN:3012:400:3012:Unrecognized AAI function +AAI_3013=5:6:WARN:3013:400:3013:Query payload missing required parameters %1 +AAI_3014=5:6:WARN:3014:400:3014:Query payload is invalid %1 +# pol errors +AAI_3100=5:1:WARN:3100:400:3100:Unsupported operation %1 +AAI_3101=5:1:WARN:3101:403:3101:Attempt by client %1 to execute API %2 +AAI_3102=5:1:WARN:3102:400:3102:Error parsing input performing %1 on %2 +AAI_3300=5:1:WARN:3300:403:3300:Unauthorized +AAI_3301=5:1:WARN:3301:401:3301:Stale credentials +AAI_3302=5:1:WARN:3302:401:3301:Not authenticated +AAI_3303=5:1:WARN:3303:403:3300:Too many objects would be returned by this request, please refine your request and retry + +#--- aaigen: 4000-4099 +AAI_4000=5:4:ERROR:4000:500:3002:Internal Error +AAI_4001=5:4:FATAL:4001:500:3002:Configuration file not found +AAI_4002=5:4:FATAL:4002:500:3002:Error reading Configuration file +AAI_4003=5:4:ERROR:4003:500:3002:Error writing to log file +AAI_4004=5:4:FATAL:4004:500:3002:Error reading/parsing the error properties file +AAI_4005=5:4:FATAL:4005:500:3002:Missing or invalid configuration parameter +AAI_4006=5:4:FATAL:4006:500:3002:Unexpected error in service +AAI_4007=5:4:WARN:4007:500:3102:Input parsing error +AAI_4008=5:4:ERROR:4008:500:3002:Output parsing error +AAI_4009=4:0:WARN:4009:400:3000:Invalid X-FromAppId in header +AAI_4010=4:0:WARN:4010:400:3000:Invalid X-TransactionId in header +AAI_4011=5:4:ERROR:4011:500:3002:Missing data for REST error response +AAI_4014=4:0:WARN:4014:400:3000:Invalid Accept header +AAI_4015=4:0:WARN:4015:400:3000:You must provide at least one indexed property +AAI_4016=4:0:WARN:4016:400:3000:The depth parameter must be a number or the string "all" +AAI_4017=5:2:INFO:4017:400:3000:Could not set property +AAI_4018=5:2:WARN:4018:400:3000:Unable to convert the string to integer +#--- aaidbmap: 5102-5199 +AAI_5102=5:4:FATAL:5102:500:3002:Graph database is null after open +AAI_5105=5:4:ERROR:5105:500:3002:Unexpected error reading/updating database +AAI_5106=5:4:WARN:5106:404:3001:Node not found +AAI_5107=5:2:WARN:5107:400:3000:Required information missing +AAI_5108=5:2:WARN:5108:200:0:Unexpected information in request being ignored + +#--- aaidbgen: 6101-6199 +AAI_6101=5:4:ERROR:6101:500:3002:null JanusGraph object passed +AAI_6102=5:4:WARN:6102:400:3000:Passed-in property is not valid for this nodeType +AAI_6103=5:4:WARN:6103:400:3000:Required Node-property not found in input data +AAI_6104=5:4:WARN:6104:400:3000:Required Node-property was passed with no data +AAI_6105=5:4:WARN:6105:400:3000:Node-Key-Property not defined in DbMaps +AAI_6106=5:4:WARN:6106:400:3000:Passed-in property is not valid for this edgeType +AAI_6107=5:4:WARN:6107:400:3000:Required Edge-property not found in input data +AAI_6108=5:4:WARN:6108:400:3000:Required Edge-property was passed with no data +AAI_6109=5:4:WARN:6109:400:3000:Bad dependent Node value +AAI_6110=5:4:ERROR:6110:400:3100:Node cannot be deleted +AAI_6111=5:4:WARN:6111:400:3000:JSON processing error +AAI_6112=5:4:ERROR:6112:400:3000:More than one node found by getUniqueNode() +AAI_6114=5:4:INFO:6114:404:3001:Node Not Found +AAI_6115=5:4:ERROR:6115:400:3000:Unrecognized NodeType +AAI_6116=5:4:ERROR:6116:400:3000:Unrecognized Property +AAI_6117=5:4:ERROR:6117:400:3000:Uniqueness constraint violated +AAI_6118=5:4:WARN:6118:400:3000:Required Field not passed. +AAI_6120=5:4:WARN:6120:400:3000:Bad Parameter Passed +AAI_6121=5:4:ERROR:6121:400:3000:Problem with internal AAI reference data +AAI_6122=5:4:ERROR:6122:400:3000:Data Set not complete in DB for this request +AAI_6123=5:4:ERROR:6123:500:3000:Bad Data found by DataGrooming Tool - Investigate +AAI_6124=5:4:ERROR:6124:500:3000:File read/write error +AAI_6125=5:4:WARN:6125:500:3000:Problem Pulling Data Set +AAI_6126=5:4:ERROR:6126:400:3000:Edge cannot be deleted +AAI_6127=5:4:INFO:6127:404:3001:Edge Not Found +AAI_6128=5:4:INFO:6128:500:3000:Unexpected error +AAI_6129=5:4:INFO:6129:404:3003:Error making edge to target node +AAI_6130=5:4:WARN:6130:412:3000:Precondition Required +AAI_6131=5:4:WARN:6131:412:3000:Precondition Failed +AAI_6132=5:4:WARN:6132:400:3000:Bad Model Definition +AAI_6133=5:4:WARN:6133:400:3000:Bad Named Query Definition +AAI_6134=5:4:ERROR:6134:500:6134:Could not persist transaction to storage back end. Exhausted retry amount +AAI_6135=5:4:WARN:6135:412:3000:Resource version specified on create +AAI_6136=5:4:ERROR:6136:400:3000:Object cannot hold multiple items +AAI_6137=5:4:ERROR:6137:400:3000:Cannot perform writes on multiple vertices +AAI_6138=5:4:ERROR:6138:400:3000:Cannot delete multiple vertices +AAI_6139=5:4:ERROR:6139:404:3000:Attempted to add edge to vertex that does not exist +AAI_6140=5:4:ERROR:6140:400:3000:Edge multiplicity violated +AAI_6141=5:4:WARN:6141:400:3000:Please Refine Query +AAI_6142=5:4:INFO:6142:400:3000:Retrying transaction +AAI_6143=5:4:INFO:6143:400:3000:Ghost vertex found +AAI_6144=5:4:WARN:6144:400:3000:Cycle found in graph +AAI_6145=5:4:ERROR:6145:400:3000:Cannot create a nested/containment edge via relationship +AAI_6146=5:4:ERROR:6146:400:3000:Ambiguous identity map found, use a URI instead +AAI_6147=5:4:ERROR:6147:400:3000:Payload Limit Reached, reduce payload +AAI_6148=5:4:INFO:6148:404:3001:Node Not Found. Start URI returned no vertexes, please check the start URI + +#--- aaicsvp: 7101-7199 +AAI_7101=5:4:ERROR:7101:500:3002:Unexpected error in CSV file processing +AAI_7102=5:4:ERROR:7102:500:3002:Error in cleanup temporary directory +#AAI_7103=4:2:ERROR:7103:500:3002:Unsupported user +AAI_7104=5:4:ERROR:7104:500:3002:Failed to create directory +AAI_7105=5:4:ERROR:7105:500:3002:Temporary directory exists +AAI_7106=5:4:ERROR:7106:500:3002:Cannot delete +AAI_7107=5:4:ERROR:7107:500:3002:Input file does not exist +AAI_7108=5:4:ERROR:7108:500:3002:Output file does not exist +AAI_7109=5:4:ERROR:7109:500:3002:Error closing file +AAI_7110=5:4:ERROR:7110:500:3002:Error loading/reading properties file +AAI_7111=5:4:ERROR:7111:500:3002:Error executing shell script +AAI_7112=5:4:ERROR:7112:500:3002:Error creating output file +AAI_7113=5:4:ERROR:7113:500:3002:Trailer record error +AAI_7114=5:4:ERROR:7114:500:3002:Input file error +AAI_7115=5:4:ERROR:7115:500:3002:Unexpected error +AAI_7116=5:4:ERROR:7116:500:3002:Request error +AAI_7117=5:4:ERROR:7117:500:3002:Error in get http client object +AAI_7118=5:4:ERROR:7118:500:3002:Script Error +AAI_7119=5:4:ERROR:7119:500:3002:Unknown host + +#--- aaisdnc: 7201-7299 +AAI_7202=5:4:ERROR:7202:500:3002:Error getting connection to odl +AAI_7203=5:4:ERROR:7203:500:3002:Unexpected error calling DataChangeNotification API +AAI_7204=5:4:ERROR:7204:500:3002:Error returned by DataChangeNotification API +#AAI_7206=5:4:ERROR:7206:500:3002:Invalid data returned from ODL + +#--- NotificationEvent, using UEB space +AAI_7350=5:4:ERROR:7305:500:3002:Notification event creation failed + +#--- aairestctlr: 7401-7499 +AAI_7401=5:4:ERROR:7401:500:3002:Error connecting to AAI REST API +AAI_7402=5:4:ERROR:7402:500:3002:Unexpected error +AAI_7403=5:4:WARN:7403:400:3001:Request error +AAI_7404=5:4:INFO:7404:404:3001:Node not found +AAI_7405=5:4:WARN:7405:200:0:UUID not formatted correctly, generating UUID +AAI_7406=5:4:ERROR:7406:400:7406:Request Timed Out + +#--- aaicsiovals: 7501-7599 +#AAI_7501=5:4:WARN:7501:500:3002:Error getting connection to CSI-OVALS +AAI_7502=5:4:WARN:7502:500:3002:Bad parameter when trying to build request for CSI-OVALS +AAI_7503=5:4:WARN:7503:500:3002:Error returned by CSI-OVALS + +#--- aaiauth: 9101-9199 +AAI_9101=5:0:WARN:9101:403:3300:User is not authorized to perform function +#AAI_9102=5:0:WARN:9102:401:3301:Refresh credentials from source +#AAI_9103=5:0:WARN:9103:403:3300:User not found +#AAI_9104=5:0:WARN:9104:401:3302:Authentication error +#AAI_9105=5:0:WARN:9105:403:3300:Authorization error +#AAI_9106=5:0:WARN:9106:403:3300:Invalid AppId +#AAI_9107=5:0:WARN:9107:403:3300:No Username in Request +AAI_9107=5:0:WARN:9107:403:3300:SSL is not provided in request, please contact admin +AAI_9108=5:0:WARN:9107:403:3300:Basic auth credentials is not provided in the request + +#--- aaiinstar: 9201-9299 +#AAI_9201=5:4:ERROR:9201:500:3002:Unable to send notification +AAI_9202=5:4:ERROR:9202:500:3002:Unable to start a thread diff --git a/src/main/resources/etc/appprops/initialcachekeyconfig.json b/src/main/resources/etc/appprops/initialcachekeyconfig.json new file mode 100644 index 0000000..f1fdabe --- /dev/null +++ b/src/main/resources/etc/appprops/initialcachekeyconfig.json @@ -0,0 +1,41 @@ +{ + "cachekeys": + [ + { + "cacheKey": "cloud-region", + "baseUrl": "https://AAI:AAI@localhost:8447", + "module": "/aai/v13/", + "URI": "cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3", + "timingIndicator": "onInit", + "httpMethod": "GET", + "parserStrategy": "aai-resource-get-all" + }, + { + "cacheKey": "complex", + "baseUrl": "https://AAI:AAI@localhost:8447", + "module": "/aai/v13/", + "URI": "cloud-infrastructure/complexes?resultIndex=1&resultSize=3", + "timingIndicator": "onInit", + "httpMethod": "GET", + "parserStrategy": "aai-resource-get-all" + }, + { + "cacheKey": "pserver", + "baseUrl": "https://AAI:AAI@localhost:8447", + "module": "/aai/v13/", + "URI": "cloud-infrastructure/pservers?depth=5807c3c3-92cd-44d7-a508-8539cd36ecda&resultIndex=1&resultSize=3", + "timingIndicator": "onInit", + "httpMethod": "GET", + "parserStrategy": "aai-resource-get-all" + }, + { + "cacheKey": "generic-vnf", + "baseUrl": "https://AAI:AAI@localhost:8447", + "module": "/aai/v13/", + "URI": "network/generic-vnfs?depth=5807c3c3-92cd-44d7-a508-8539cd36ecda&resultIndex=1&resultSize=3", + "timingIndicator": "onInit", + "httpMethod": "GET", + "parserStrategy": "aai-resource-get-all" + } + ] +}
\ No newline at end of file diff --git a/src/main/resources/etc/appprops/preferredRoute.txt b/src/main/resources/etc/appprops/preferredRoute.txt new file mode 100644 index 0000000..a0290a1 --- /dev/null +++ b/src/main/resources/etc/appprops/preferredRoute.txt @@ -0,0 +1 @@ +MR1
\ No newline at end of file diff --git a/src/main/resources/etc/auth/aai-client-cert.p12 b/src/main/resources/etc/auth/aai-client-cert.p12 Binary files differnew file mode 100644 index 0000000..292efb7 --- /dev/null +++ b/src/main/resources/etc/auth/aai-client-cert.p12 diff --git a/src/main/resources/etc/auth/aai_keystore b/src/main/resources/etc/auth/aai_keystore Binary files differnew file mode 100644 index 0000000..16d93a7 --- /dev/null +++ b/src/main/resources/etc/auth/aai_keystore diff --git a/src/main/resources/etc/auth/realm.properties b/src/main/resources/etc/auth/realm.properties new file mode 100644 index 0000000..fb692cc --- /dev/null +++ b/src/main/resources/etc/auth/realm.properties @@ -0,0 +1,12 @@ +# format : username: password[,rolename ...] +# default username/password: AAI/AAI, MSO/MSO, ModelLoader/ModelLoader... +AAI:OBF:1gfr1ev31gg7,admin +MSO:OBF:1jzx1lz31k01,admin +SDNC:OBF:1itr1i0l1i151isv,admin +DCAE:OBF:1g8u1f9d1f991g8w,admin +POLICY:OBF:1mk61i171ima1im41i0j1mko,admin +ASDC:OBF:1f991j0u1j001f9d,admin +VID:OBF:1jm91i0v1jl9,admin +APPC:OBF:1f991ksf1ksf1f9d,admin +ModelLoader:OBF:1qvu1v2h1sov1sar1wfw1j7j1wg21saj1sov1v1x1qxw,admin +AaiUI:OBF:1gfr1p571unz1p4j1gg7,admin diff --git a/src/main/resources/localhost-access-logback.xml b/src/main/resources/localhost-access-logback.xml new file mode 100644 index 0000000..a318796 --- /dev/null +++ b/src/main/resources/localhost-access-logback.xml @@ -0,0 +1,62 @@ +<!-- + + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 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========================================================= + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + +--> +<configuration> + <property name="AJSC_HOME" value="${AJSC_HOME:-.}" /> + <appender name="ACCESS" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${AJSC_HOME}/logs/ajsc-jetty/localhost_access.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${AJSC_HOME}/logs/ajsc-jetty/localhost_access.log.%d{yyyy-MM-dd} + </fileNamePattern> + </rollingPolicy> + <encoder class="org.onap.aai.logging.CustomLogPatternLayoutEncoder"> + <Pattern>%a %u %z [%t] "%m %U%q" %s %b %y %i{X-TransactionId} %i{X-FromAppId} %i{X-Forwarded-For} %i{X-AAI-SSL-Client-CN} %i{X-AAI-SSL-Client-OU} %i{X-AAI-SSL-Client-O} %i{X-AAI-SSL-Client-L} %i{X-AAI-SSL-Client-ST} %i{X-AAI-SSL-Client-C} %i{X-AAI-SSL-Client-NotBefore} %i{X-AAI-SSL-Client-NotAfter} %i{X-AAI-SSL-Client-DN} %D</Pattern> + </encoder> + </appender> + <appender-ref ref="ACCESS" /> +</configuration> + +<!-- +%a - Remote IP address +%A - Local IP address +%b - Bytes sent, excluding HTTP headers, or '-' if no bytes were sent +%B - Bytes sent, excluding HTTP headers +%h - Remote host name +%H - Request protocol +%l - Remote logical username from identd (always returns '-') +%m - Request method +%p - Local port +%q - Query string (prepended with a '?' if it exists, otherwise an empty string +%r - First line of the request +%s - HTTP status code of the response +%S - User session ID +%t - Date and time, in Common Log Format format +%u - Remote user that was authenticated +%U - Requested URL path +%v - Local server name +%I - current request thread name (can compare later with stacktraces) + +%z - Custom pattern that parses the cert for the subject +%y - Custom pattern determines rest or dme2 + -->
\ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..9caabe6 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,243 @@ +<!-- + + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 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========================================================= + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + +--> +<configuration scan="true" scanPeriod="60 seconds" debug="false"> + <statusListener class="ch.qos.logback.core.status.NopStatusListener" /> + + <property resource="application.properties" /> + + <property name="namespace" value="aai-cacher"/> + + <property name="AJSC_HOME" value="${AJSC_HOME:-.}" /> + <jmxConfigurator /> + <property name="logDirectory" value="${AJSC_HOME}/logs" /> + <property name="eelfLogPattern" value="%ecompStartTime|%date{yyyy-MM-dd'T'HH:mm:ss.SSSZ, UTC}|%X{requestId}|%X{serviceInstanceId}|%-10t|%X{serverName}|%X{serviceName}|%X{partnerName}|%ecompStatusCode|%X{responseCode}|%replace(%replace(%X{responseDescription}){'\\|', '!'}){'\r|\n', '^'}|%X{instanceUUID}|%level|%X{severity}|%X{serverIpAddress}|%ecompElapsedTime|%X{server}|%X{clientIpAddress}|%eelfClassOfCaller|%X{unused}|%X{processKey}|%X{customField1}|%X{customField2}|%X{customField3}|%X{customField4}|co=%X{component}:%replace(%replace(%m){'\\|', '!'}){'\r|\n', '^'}%n"/> + <property name="eelfMetricLogPattern" value="%ecompStartTime|%date{yyyy-MM-dd'T'HH:mm:ss.SSSZ, UTC}|%X{requestId}|%X{serviceInstanceId}|%-10t|%X{serverName}|%X{serviceName}|%X{partnerName}|%X{targetEntity}|%X{targetServiceName}|%ecompStatusCode|%X{responseCode}|%replace(%replace(%X{responseDescription}){'\\|', '!'}){'\r|\n', '^'}|%X{instanceUUID}|%level|%X{severity}|%X{serverIpAddress}|%ecompElapsedTime|%X{server}|%X{clientIpAddress}|%eelfClassOfCaller|%X{unused}|%X{processKey}|%X{targetVirtualEntity}|%X{customField1}|%X{customField2}|%X{customField3}|%X{customField4}|co=%X{component}:%replace(%replace(%m){'\\|', '!'}){'\r|\n', '^'}%n"/> + <!-- <property name="eelfErrorLogPattern" value="%ecompStartTime|%X{requestId}|%-10t|%X{serviceName}|%X{partnerName}|%X{targetEntity}|%X{targetServiceName}|%ecompErrorCategory|%X{responseCode}|%replace(%replace(%X{responseDescription}){'\\|', '!'}){'\r|\n|\r\n', '^'}|co=%X{component}:%replace(%replace(%m){'\\|', '!'}){'\r|\n', '^'}%n"/> --> + <property name="eelfErrorLogPattern" value="%ecompStartTime|%X{requestId}|%-10t|%X{serviceName}|%X{partnerName}|%X{targetEntity}|%X{targetServiceName}|%ecompErrorCategory|%ecompResponseCode|%ecompResponseDescription|co=%X{component}:%replace(%replace(%m){'\\|', '!'}){'\r|\n', '^'}%n"/> + <property name="eelfTransLogPattern" value="%ecompStartTime|%date{yyyy-MM-dd'T'HH:mm:ss.SSSZ, UTC}|%X{requestId}|%X{serviceInstanceId}|%-10t|%X{serverName}|%X{serviceName}|%X{partnerName}|%ecompStatusCode|%X{responseCode}|%replace(%replace(%X{responseDescription}){'\\|', '!'}){'\r|\n', '^'}|%X{instanceUUID}|%level|%X{severity}|%X{serverIpAddress}|%ecompElapsedTime|%X{server}|%X{clientIpAddress}|%eelfClassOfCaller|%X{unused}|%X{processKey}|%X{customField1}|%X{customField2}|%X{customField3}|%X{customField4}|co=%X{partnerName}:%m%n"/> + + <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> + <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> + <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern> + %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} + </pattern> + </encoder> + </appender> + + <appender name="SANE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/rest/sane.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/rest/sane.log.%d{yyyy-MM-dd}</fileNamePattern> + </rollingPolicy> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - %msg%n + </pattern> + </encoder> + </appender> + + <appender name="asyncSANE" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>1000</queueSize> + <includeCallerData>true</includeCallerData> + <appender-ref ref="SANE" /> + </appender> + + <appender name="METRIC" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>INFO</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>${logDirectory}/rest/metrics.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/rest/metrics.log.%d{yyyy-MM-dd} + </fileNamePattern> + </rollingPolicy> + <encoder class="org.onap.aai.logging.EcompEncoder"> + <pattern>${eelfMetricLogPattern}</pattern> + </encoder> + </appender> + <appender name="asyncMETRIC" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>1000</queueSize> + <includeCallerData>true</includeCallerData> + <appender-ref ref="METRIC" /> + </appender> + + <appender name="DEBUG" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>DEBUG</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>${logDirectory}/rest/debug.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/rest/debug.log.%d{yyyy-MM-dd} + </fileNamePattern> + </rollingPolicy> + <encoder class="org.onap.aai.logging.EcompEncoder"> + <pattern>${eelfLogPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncDEBUG" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>1000</queueSize> + <includeCallerData>true</includeCallerData> + <appender-ref ref="DEBUG" /> + </appender> + + <appender name="ERROR" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> + <level>WARN</level> + </filter> + <file>${logDirectory}/rest/error.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/rest/error.log.%d{yyyy-MM-dd} + </fileNamePattern> + </rollingPolicy> + <encoder class="org.onap.aai.logging.EcompEncoder"> + <pattern>${eelfErrorLogPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncERROR" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>1000</queueSize> + <includeCallerData>true</includeCallerData> + <appender-ref ref="ERROR" /> + </appender> + + + + <appender name="translog" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>DEBUG</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>${logDirectory}/rest/translog.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/rest/translog.log.%d{yyyy-MM-dd} + </fileNamePattern> + </rollingPolicy> + <encoder class="org.onap.aai.logging.EcompEncoder"> + <pattern>${eelfTransLogPattern}</pattern> + </encoder> + </appender> + + <appender name="asynctranslog" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>1000</queueSize> + <includeCallerData>true</includeCallerData> + <appender-ref ref="translog" /> + </appender> + + <appender name="external" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> + <level>WARN</level> + </filter> + <file>${logDirectory}/external/external.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${logDirectory}/external/external.log.%d{yyyy-MM-dd} + </fileNamePattern> + </rollingPolicy> + <encoder class="org.onap.aai.logging.EcompEncoder"> + <pattern>${eelfLogPattern}</pattern> + </encoder> + </appender> + <logger name="org.onap.aai.cacher" level="DEBUG" additivity="false"> + <appender-ref ref="asyncDEBUG" /> + <appender-ref ref="asyncERROR" /> + <appender-ref ref="asyncMETRIC" /> + <appender-ref ref="asyncSANE" /> + </logger> + + <!-- Spring related loggers --> + <logger name="org.springframework" level="WARN" /> + <logger name="org.springframework.beans" level="WARN" /> + <logger name="org.springframework.web" level="WARN" /> + <logger name="com.blog.spring.jms" level="WARN" /> + <logger name="com.jayway.jsonpath" level="WARN" /> + + <logger name="com.netflix.loadbalancer" level="WARN" /> + + <logger name="org.apache.zookeeper" level="OFF" /> + + <!-- Other Loggers that may help troubleshoot --> + <logger name="net.sf" level="WARN" /> + <logger name="org.apache.commons.httpclient" level="WARN" /> + <logger name="org.apache.commons" level="WARN" /> + <logger name="org.apache.coyote" level="WARN" /> + <logger name="org.apache.jasper" level="WARN" /> + + <!-- Camel Related Loggers (including restlet/servlet/jaxrs/cxf logging. + May aid in troubleshooting) --> + <logger name="org.apache.camel" level="WARN" /> + <logger name="org.apache.cxf" level="WARN" /> + <logger name="org.apache.camel.processor.interceptor" level="WARN" /> + <logger name="org.apache.cxf.jaxrs.interceptor" level="WARN" /> + <logger name="org.apache.cxf.service" level="WARN" /> + <logger name="org.restlet" level="WARN" /> + <logger name="org.apache.camel.component.restlet" level="WARN" /> + + <logger name="org.hibernate.validator" level="WARN" /> + <logger name="org.hibernate" level="WARN" /> + <logger name="org.hibernate.ejb" level="OFF" /> + + <!-- logback internals logging --> + <logger name="ch.qos.logback.classic" level="WARN" /> + <logger name="ch.qos.logback.core" level="WARN" /> + + <logger name="org.eclipse.jetty" level="WARN" /> + + + <!-- logback jms appenders & loggers definition ends here --> + + <logger name="org.onap.aai.interceptors.post" level="DEBUG" + additivity="false"> + <appender-ref ref="asynctranslog" /> + </logger> + + <logger name="org.apache" level="OFF" /> + <logger name="org.zookeeper" level="OFF" /> + <logger name="org.janusgraph" level="WARN" /> + <logger name="com.att.aft.dme2" level="WARN" /> + + <!-- ============================================================================ --> + <!-- General EELF logger --> + <!-- ============================================================================ --> + <logger name="com.att.eelf" level="WARN" additivity="false"> + <appender-ref ref="asyncDEBUG" /> + <appender-ref ref="asyncERROR" /> + <appender-ref ref="asyncMETRIC" /> + </logger> + + <root level="DEBUG"> + <appender-ref ref="external" /> + </root> +</configuration> diff --git a/src/test/java/org/onap/aai/cacher/common/MongoHelperSingletonNoFakeTest.java b/src/test/java/org/onap/aai/cacher/common/MongoHelperSingletonNoFakeTest.java new file mode 100644 index 0000000..1a086bc --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/common/MongoHelperSingletonNoFakeTest.java @@ -0,0 +1,490 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.common; + +import com.google.gson.JsonParser; +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.UpdateOptions; +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodProcess; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongoCmdOptionsBuilder; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; +import org.bson.Document; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.*; +import org.onap.aai.cacher.dmaap.consumer.AAIDmaapEventProcessorScenariosTest; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.cacher.model.DBAction; +import org.skyscreamer.jsonassert.JSONAssert; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +public class MongoHelperSingletonNoFakeTest { + + private static final String DB_NAME = AAIDmaapEventProcessorScenariosTest.class.getSimpleName(); + private static MongoDatabase mongoDatabase; + private static DB db; + private static MongodProcess mongod; + private static MongoClient mongoC; + + private MongoHelperSingleton mongoHelperSingleton; + private JsonParser parser = new JsonParser(); + + + @BeforeClass + public static void setup() throws IOException, InterruptedException { + + String bindIp = "localhost"; + int port = 27017; + startEmbedded(port); + + mongoC = new MongoClient(bindIp, port); + mongoDatabase = mongoC.getDatabase(DB_NAME); + db = mongoC.getDB(DB_NAME); + + } + + protected static void startEmbedded(int port) throws IOException { + IMongodConfig mongoConfigConfig = new MongodConfigBuilder() + .version(Version.Main.PRODUCTION) + .net(new Net(port, Network.localhostIsIPv6())) + .cmdOptions(new MongoCmdOptionsBuilder().verbose(true).build()) + .configServer(false) + .build(); + + MongodExecutable mongodExecutable = MongodStarter.getDefaultInstance().prepare(mongoConfigConfig); + + mongod = mongodExecutable.start(); + } + + @AfterClass + public static void tearDown() { + if (mongod != null && mongod.isProcessRunning()) { + mongod.stop(); + } + } + + @Before + public void init() { + mongoHelperSingleton = new MongoHelperSingleton(db, mongoDatabase); + } + + @After + public void cleanup() { + final List<String> collectionNames = new ArrayList<>(); + mongoDatabase.listCollections().iterator().forEachRemaining(document -> collectionNames.add(document.getString("name"))); + collectionNames.stream().forEach(collectionName -> mongoDatabase.getCollection(collectionName).drop()); + } + + + private MongoCollection<Document> setupCollection(String collectionName) { + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'}"); + Document obj = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1','hostname':'testPserver_1'," + + "'p-interfaces':{'p-interface':[" + + "{'interface-name':'interface-1','l-interfaces':{'l-interface':[{'interface-name':'l-interface-1','test':'test'}]}}," + + "{'interface-name':'interface-2'}" + + "]}}"); + collection.replaceOne(findQuery, obj, new UpdateOptions().upsert(true)); + + + findQuery = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}"); + obj = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2','hostname':'testPserver_2'," + + "'p-interfaces':{'p-interface':[" + + "{'interface-name':'interface-1','l-interfaces':{'l-interface':[{'interface-name':'l-interface-1'}]}}," + + "{'interface-name':'interface-2'}" + + "]}}"); + collection.replaceOne(findQuery, obj, new UpdateOptions().upsert(true)); + + findQuery = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99'}"); + obj = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99','hostname':'testPserver_99'," + + "'p-interfaces':{'p-interface':[" + + "{'interface-name':'interface-1','l-interfaces':{'l-interface':[{'interface-name':'l-interface-1','l3-interface-ipv4-address-list':[{'l3-interface-ipv4-address':'address'}]}]}}," + + "{'interface-name':'interface-2'}" + + "]}}"); + collection.replaceOne(findQuery, obj, new UpdateOptions().upsert(true)); + + assertEquals("Pre " + collectionName + " test: collection contains 3 documents", 3L, collection.count()); + + return collection; + } + + @Test + public void getNestedObjectAddressList() throws JSONException { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99'," + + "'hostname':'testPserver_99'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.l3-interface-ipv4-address-list.l3-interface-ipv4-address':'address'}"; + CacheEntry ce = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .isNested(true) + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()).build(); + + Optional<Document> nested = mongoHelperSingleton.getObject(ce); + + assertTrue(nested.isPresent()); + + JSONAssert.assertEquals( + new JSONObject("{'l3-interface-ipv4-address':'address'}"), + new JSONObject(nested.get().toJson()), + true); + + + } + + @Test + public void getNestedObject() throws JSONException { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99'," + + "'hostname':'testPserver_99'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'}"; + CacheEntry ce = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .isNested(true) + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()).build(); + + Optional<Document> nested = mongoHelperSingleton.getObject(ce); + + assertTrue(nested.isPresent()); + JSONAssert.assertEquals( + new JSONObject("{'interface-name':'l-interface-1','l3-interface-ipv4-address-list':[{'l3-interface-ipv4-address':'address'}]}"), + new JSONObject(nested.get().toJson()), + true); + + } + + @Test + public void insertNewTop() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(false) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_3") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_3'}").getAsJsonObject()) + .withPayload(parser.parse("{'hostname':'testPserver_1'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 4 document", 4L, collection.count()); + + } + + @Test + public void insertNewNested() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-NEW'}"; + Document nestedFind = Document.parse(nestedFindString); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_1") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'}").getAsJsonObject()) + .withPayload(parser.parse("{'interface-name':'interface-NEW'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'interface-NEW'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + + } + + @Test + public void insertNewTwoNested() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-NEW'}"; + Document nestedFind = Document.parse(nestedFindString); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_1") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}").getAsJsonObject()) + .withPayload(parser.parse("{'interface-name':'l-interface-NEW','new-field':'NEW'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface.$.l-interfaces.l-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'l-interface-NEW'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + + } + + @Test + public void insertNewThreeNested() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.vlans.vlan.vlan-interface':'vlan-NEW'}"; + Document nestedFind = Document.parse(nestedFindString); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_1") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'}").getAsJsonObject()) + .withPayload(parser.parse("{'vlan-interface':'vlan-NEW','new-field':'NEW4'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface.$.l-interfaces.l-interface.$.vlans.vlan") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'vlan-interface':'vlan-NEW'}").getAsJsonObject()) + .build(); + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + + } + + + @Test + public void insertExstingNested() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}"; + Document nestedFind = Document.parse(nestedFindString); + + String newNestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.new-field':'NEW'}"; + Document newNestedFind = Document.parse(newNestedFindString); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_1") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'}").getAsJsonObject()) + .withPayload(parser.parse("{'interface-name':'interface-1','new-field':'NEW'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'interface-1'}").getAsJsonObject()) + .build(); + + assertEquals("Pre " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested property", 1L, collection.count(newNestedFind)); + + } + + @Test + public void replaceTop() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + + MongoCollection<Document> collection = setupCollection(collectionName); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(false) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}").getAsJsonObject()) + .withPayload(parser.parse("{'hostname':'testPserver_2','new-property':'NEW'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 3 document", 3L, collection.count()); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new property", + 1L, + collection.count(Document.parse("{'new-property':'NEW'}"))); + + + } + + @Test + public void deleteTopLevel() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.DELETE) + .isNested(false) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.delete(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 2 document", 2L, collection.count()); + + } + + @Test + public void deleteNestedOneLevel() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}"; + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("Pre " + collectionName + " test: collection contains 1 document with filter", + 1L, + collection.count(nestedFind)); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.DELETE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'interface-1'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.delete(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 0 document", + 0L, + collection.count(nestedFind)); + + } + + @Test + public void deleteNestedTwoLevel() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'}"; + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("Pre " + collectionName + " test: collection contains 1 document with filter", + 1L, + collection.count(nestedFind)); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.DELETE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface.$.l-interfaces.l-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'l-interface-1'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.delete(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 0 document", + 0L, + collection.count(nestedFind)); + + + } + + //TODO delete non existent top + + +}
\ No newline at end of file diff --git a/src/test/java/org/onap/aai/cacher/common/MongoHelperSingletonTest.java b/src/test/java/org/onap/aai/cacher/common/MongoHelperSingletonTest.java new file mode 100644 index 0000000..872f099 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/common/MongoHelperSingletonTest.java @@ -0,0 +1,417 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.common; + +import com.github.fakemongo.Fongo; +import com.google.gson.JsonParser; +import com.mongodb.DB; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.UpdateOptions; +import org.bson.Document; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.aai.cacher.model.CacheEntry; +import org.onap.aai.cacher.model.DBAction; +import org.skyscreamer.jsonassert.JSONAssert; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class MongoHelperSingletonTest { + + private static final String DB_NAME = "testDb"; + private static MongoDatabase mongoDatabase; + private static DB db; + private MongoHelperSingleton mongoHelperSingleton; + private JsonParser parser = new JsonParser(); + + + @BeforeClass + public static void setup() { + Fongo fongo = new Fongo(DB_NAME); + mongoDatabase = fongo.getDatabase(DB_NAME); + db = fongo.getDB(DB_NAME); + } + + @Before + public void init() { + mongoHelperSingleton = new MongoHelperSingleton(db, mongoDatabase); + } + + @After + public void cleanup() { + final List<String> collectionNames = new ArrayList<>(); + mongoDatabase.listCollections().iterator().forEachRemaining(document -> collectionNames.add(document.getString("name"))); + collectionNames.stream().forEach(collectionName -> mongoDatabase.getCollection(collectionName).drop()); + } + + private MongoCollection<Document> setupCollection(String collectionName) { + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'}"); + Document obj = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1','hostname':'testPserver_1'," + + "'p-interfaces':{'p-interface':[" + + "{'interface-name':'interface-1','l-interfaces':{'l-interface':[{'interface-name':'l-interface-1','test':'test'}]}}," + + "{'interface-name':'interface-2'}" + + "]}}"); + collection.replaceOne(findQuery, obj, new UpdateOptions().upsert(true)); + + + findQuery = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}"); + obj = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2','hostname':'testPserver_2'," + + "'p-interfaces':{'p-interface':[" + + "{'interface-name':'interface-1','l-interfaces':{'l-interface':[{'interface-name':'l-interface-1'}]}}," + + "{'interface-name':'interface-2'}" + + "]}}"); + collection.replaceOne(findQuery, obj, new UpdateOptions().upsert(true)); + + findQuery = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99'}"); + obj = Document.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99','hostname':'testPserver_99'," + + "'p-interfaces':{'p-interface':[" + + "{'interface-name':'interface-1','l-interfaces':{'l-interface':[{'interface-name':'l-interface-1','l3-interface-ipv4-address-list':[{'l3-interface-ipv4-address':'address'}]}]}}," + + "{'interface-name':'interface-2'}" + + "]}}"); + collection.replaceOne(findQuery, obj, new UpdateOptions().upsert(true)); + + assertEquals("Pre " + collectionName + " test: collection contains 3 documents", 3L, collection.count()); + + return collection; + } + + @Test + public void getNestedObjectAddressList() throws JSONException { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99'," + + "'hostname':'testPserver_99'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.l3-interface-ipv4-address-list.l3-interface-ipv4-address':'address'}"; + CacheEntry ce = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .isNested(true) + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()).build(); + + Optional<Document> nested = mongoHelperSingleton.getObject(ce); + + assertTrue(nested.isPresent()); + + JSONAssert.assertEquals( + new JSONObject("{'l3-interface-ipv4-address':'address'}"), + new JSONObject(nested.get().toJson()), + true); + + + } + + @Test + public void getNestedObject() throws JSONException { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_99'," + + "'hostname':'testPserver_99'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'}"; + CacheEntry ce = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .isNested(true) + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()).build(); + + Optional<Document> nested = mongoHelperSingleton.getObject(ce); + + assertTrue(nested.isPresent()); + JSONAssert.assertEquals( + new JSONObject("{'interface-name':'l-interface-1','l3-interface-ipv4-address-list':[{'l3-interface-ipv4-address':'address'}]}"), + new JSONObject(nested.get().toJson()), + true); + } + + @Test + public void insertNewTop() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + setupCollection(collectionName); + + MongoCollection<Document> collection = setupCollection(collectionName); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(false) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_3") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_3'}").getAsJsonObject()) + .withPayload(parser.parse("{'hostname':'testPserver_1'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 4 document", 4L, collection.count()); + + } + + @Test + public void insertNewNested() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + setupCollection(collectionName); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-NEW'}"; + Document nestedFind = Document.parse(nestedFindString); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_1") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'}").getAsJsonObject()) + .withPayload(parser.parse("{'interface-name':'interface-NEW'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'interface-NEW'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + + } + + @Test + public void insertNewTwoNested() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + setupCollection(collectionName); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-NEW'}"; + Document nestedFind = Document.parse(nestedFindString); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_1") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}").getAsJsonObject()) + .withPayload(parser.parse("{'interface-name':'l-interface-NEW','new-field':'NEW'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface.$.l-interfaces.l-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'l-interface-NEW'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + + } + + + @Test + public void insertExstingNested() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + setupCollection(collectionName); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}"; + Document nestedFind = Document.parse(nestedFindString); + + String newNestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.new-field':'NEW'}"; + Document newNestedFind = Document.parse(newNestedFindString); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_1") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'}").getAsJsonObject()) + .withPayload(parser.parse("{'interface-name':'interface-1','new-field':'NEW'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'interface-1'}").getAsJsonObject()) + .build(); + + assertEquals("Pre " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested", 1L, collection.count(nestedFind)); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new nested property", 1L, collection.count(newNestedFind)); + + } + + @Test + public void replaceTop() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + setupCollection(collectionName); + + MongoCollection<Document> collection = setupCollection(collectionName); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.INSERT_REPLACE) + .isNested(false) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}").getAsJsonObject()) + .withPayload(parser.parse("{'hostname':'testPserver_2','new-property':'NEW'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.insertReplace(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 3 document", 3L, collection.count()); + assertEquals("Post " + collectionName + " test: collection contains 1 document with new property", + 1L, + collection.count(Document.parse("{'new-property':'NEW'}"))); + + + } + + @Test + public void deleteTopLevel() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.DELETE) + .isNested(false) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.delete(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 2 document", 2L, collection.count()); + + } + + @Test + public void deleteNestedOneLevel() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}"; + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("Pre " + collectionName + " test: collection contains 1 document with filter", + 1L, + collection.count(nestedFind)); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.DELETE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'interface-1'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.delete(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 0 document", + 0L, + collection.count(nestedFind)); + + } + + @Test + public void deleteNestedTwoLevel() throws Exception { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + MongoCollection<Document> collection = setupCollection(collectionName); + + String nestedFindString = "{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_1'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'l-interface-1'}"; + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("Pre " + collectionName + " test: collection contains 1 document with filter", + 1L, + collection.count(nestedFind)); + + CacheEntry cacheEntry = CacheEntry.CacheEntryBuilder.createCacheEntry() + .inCollection(collectionName) + .withDbAction(DBAction.DELETE) + .isNested(true) + .withId("/cloud-infrastructure/pservers/pserver/testPserver_2") + .withFindQuery(parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/testPserver_2'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}").getAsJsonObject()) + .withNestedField("p-interfaces.p-interface.$.l-interfaces.l-interface") + .withNestedFind(parser.parse(nestedFindString).getAsJsonObject()) + .withNestedFieldIdentifierObj(parser.parse("{'interface-name':'l-interface-1'}").getAsJsonObject()) + .build(); + + assertTrue(mongoHelperSingleton.delete(cacheEntry)); + assertEquals("Post " + collectionName + " test: collection contains 0 document", + 0L, + collection.count(nestedFind)); + + } + + //TODO delete non existent top + + +}
\ No newline at end of file diff --git a/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessorScenariosTest.java b/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessorScenariosTest.java new file mode 100644 index 0000000..2c01f5a --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessorScenariosTest.java @@ -0,0 +1,496 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import com.google.gson.JsonParser; +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoDatabase; +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodProcess; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongoCmdOptionsBuilder; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; +import org.apache.commons.io.IOUtils; +import org.bson.Document; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aai.cacher.common.MongoHelperSingleton; +import org.onap.aai.cacher.injestion.parser.InjestionTestComponent; +import org.onap.aai.cacher.injestion.parser.PayloadParserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.TestCase.assertFalse; +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@Configuration +@ContextConfiguration(classes = {InjestionTestComponent.class, AAIDmaapEventProcessorScenariosTest.class}) +public class AAIDmaapEventProcessorScenariosTest { + + private static final String DB_NAME = AAIDmaapEventProcessorScenariosTest.class.getSimpleName(); + private static MongoDatabase mongoDb; + private static DB db; + private static MongodProcess mongod; + private static MongoClient mongoC; + + private JsonParser parser = new JsonParser(); + + @Autowired + private AAIDmaapEventProcessor aaiDmaapEventProcessor; + + @Bean + public DB db() { + return db; + } + + @Bean + public MongoDatabase mongoDatabase() { + return mongoDb; + } + + @Bean + public MongoHelperSingleton mongoHelperSingleton(DB db, MongoDatabase mongoDb) { + return new MongoHelperSingleton(db, mongoDb); + } + + @Bean + public AAIDmaapEventProcessor aaiDmaapEventProcessor(MongoHelperSingleton mongoHelperSingleton, PayloadParserService payloadParserService) { + return new AAIDmaapEventProcessor(mongoHelperSingleton, payloadParserService); + } + + @BeforeClass + public static void setup() throws IOException, InterruptedException { + + String bindIp = "localhost"; + int port = 27017; + startEmbedded(port); + + mongoC = new MongoClient(bindIp, port); + mongoDb = mongoC.getDatabase(DB_NAME); + db = mongoC.getDB(DB_NAME); + + } + + protected static void startEmbedded(int port) throws IOException { + IMongodConfig mongoConfigConfig = new MongodConfigBuilder() + .version(Version.Main.PRODUCTION) + .net(new Net(port, Network.localhostIsIPv6())) + .cmdOptions(new MongoCmdOptionsBuilder().verbose(true).build()) + .configServer(false) + .build(); + + MongodExecutable mongodExecutable = MongodStarter.getDefaultInstance().prepare(mongoConfigConfig); + + mongod = mongodExecutable.start(); + } + + @AfterClass + public static void tearDown() { + if (mongod != null && mongod.isProcessRunning()) { + mongod.stop(); + } + } + + @After + public void cleanup() { + final List<String> collectionNames = new ArrayList<>(); + mongoDb.listCollections().iterator().forEachRemaining(document -> collectionNames.add(document.getString("name"))); + collectionNames.forEach(collectionName -> mongoDb.getCollection(collectionName).drop()); + } + + + @Test + public void createPserverCreateCRWithNestingAndRelationshipsToTest() throws Exception { + String pserverCreate = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false}}"; + + aaiDmaapEventProcessor.process(pserverCreate); + assertNotEquals("pserver collection exists", mongoDatabase().getCollection("pserver"), null); + assertEquals("pserver collection contains 1", mongoDatabase().getCollection("pserver").count(), 1); + assertTrue("pserver collection contains the pserver in the event", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("pserver should not have relationship to vserver", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("pserver should not have relationship to l-interface", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1'" + + "}")) + .iterator().hasNext() + ); + + + String crWithNestingAndWithRels = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'cloud-region','top-entity-type':'cloud-region','entity-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'3d567832-df00-49b5-b862-4d3a341dbec1','source-name':'JUNIT','version':'v13','timestamp':'20180515-10:57:55:750'},'entity':{'tenants':{'tenant':[{'vservers':{'vserver':[{'relationship-list':{'relationship':[{'related-to':'pserver','relationship-data':[{'relationship-value':'pserver-1','relationship-key':'pserver.hostname'}],'related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','relationship-label':'tosca.relationships.HostedOn'}]},'l-interfaces':{'l-interface':[{'interface-name':'l-int-1','interface-id':'l-int-1','l3-interface-ipv4-address-list':[{'neutron-network-id':'93fb399c-9bfc-4234-b2bb-a76eda38f117','neutron-subnet-id':'79e5bb69-24bb-4ea3-8d1d-c04fca5f5e1e','l3-interface-ipv4-address':'192.168.70.3'}],'relationship-list':{'relationship':[{'related-to':'pserver','relationship-data':[{'relationship-value':'pserver-1','relationship-key':'pserver.hostname'}],'related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','relationship-label':'tosca.relationships.HostedOn'}]}}]},'vserver-id':'vserver-1'}]},'tenant-id':'tenenat-1'}]},'cloud-owner':'onap-cloud-owner','cloud-region-id':'mtn6'}}"; + + aaiDmaapEventProcessor.process(crWithNestingAndWithRels); + + assertNotEquals("cloud-region collection exists", mongoDatabase().getCollection("cloud-region"), null); + assertTrue("Now pserver has relationship to vserver", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1'" + + "}")) + .iterator().hasNext() + ); + assertTrue("Now pserver has relationship to l-interface", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1'" + + "}")) + .iterator().hasNext() + ); + } + + + @Test + public void createCRWithNestingCreatePserverRelationshipsToNestedTest() throws Exception { + String crWithNesting = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'cloud-region','top-entity-type':'cloud-region','entity-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'3d567832-df00-49b5-b862-4d3a341dbec1','source-name':'JUNIT','version':'v13','timestamp':'20180515-10:57:55:750'},'entity':{'tenants':{'tenant':[{'vservers':{'vserver':[{'l-interfaces':{'l-interface':[{'interface-name':'l-int-1','interface-id':'l-int-1','l3-interface-ipv4-address-list':[{'neutron-network-id':'93fb399c-9bfc-4234-b2bb-a76eda38f117','neutron-subnet-id':'79e5bb69-24bb-4ea3-8d1d-c04fca5f5e1e','l3-interface-ipv4-address':'192.168.70.3'}]}]},'vserver-id':'vserver-1'}]},'tenant-id':'tenenat-1'}]},'cloud-owner':'onap-cloud-owner','cloud-region-id':'mtn6'}}"; + + aaiDmaapEventProcessor.process(crWithNesting); + + assertNotEquals("cloud-region collection exists", mongoDatabase().getCollection("cloud-region"), null); + + String pserverWithRelsToNested = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false,'relationship-list':{'relationship':[{'related-to':'vserver','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'},{'relationship-key':'tenant.tenant-id','relationship-value':'tenenat-1'},{'relationship-key':'vserver.vserver-id','relationship-value':'vserver-1'}]},{'related-to':'l-interface','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'},{'relationship-key':'tenant.tenant-id','relationship-value':'tenenat-1'},{'relationship-key':'vserver.vserver-id','relationship-value':'vserver-1'},{'relationship-key':'l-interface.interface-name','relationship-value':'l-int-1'}]}]}}}"; + + aaiDmaapEventProcessor.process(pserverWithRelsToNested); + assertTrue("Now cloud-region->tenant->vserver now has relationship to pserver", + mongoDatabase().getCollection("cloud-region") + .find(Document.parse("{" + + "'cloud-owner':'onap-cloud-owner'," + + "'cloud-region-id':'mtn6'," + + "'tenants.tenant.tenant-id':'tenenat-1'," + + "'tenants.tenant.vservers.vserver.vserver-id':'vserver-1'," + + "'tenants.tenant.vservers.vserver.relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1'" + + "}")) + .iterator().hasNext() + ); + assertTrue("Now cloud-region->tenant->vserver->l-interface now has relationship to pserver", + mongoDatabase().getCollection("cloud-region") + .find(Document.parse("{" + + "'cloud-owner':'onap-cloud-owner'," + + "'cloud-region-id':'mtn6'," + + "'tenants.tenant.tenant-id':'tenenat-1'," + + "'tenants.tenant.vservers.vserver.vserver-id':'vserver-1'," + + "'tenants.tenant.vservers.vserver.l-interfaces.l-interface.interface-name':'l-int-1'," + + "'tenants.tenant.vservers.vserver.relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1'" + + "}")) + .iterator().hasNext() + ); + } + + @Ignore + @Test + public void createPserverCreateCRWithNestingAndRelsToUpdateRemovingARelTest() throws Exception { + String pserverCreate = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false}}"; + + aaiDmaapEventProcessor.process(pserverCreate); + assertNotEquals("pserver collection exists", mongoDatabase().getCollection("pserver"), null); + assertEquals("pserver collection contains 1", mongoDatabase().getCollection("pserver").count(), 1); + assertTrue("pserver collection contains the pserver in the event", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("pserver should not have relationship to vserver", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("pserver should not have relationship to l-interface", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1'" + + "}")) + .iterator().hasNext() + ); + + + String crWithNestingAndWithRels = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'cloud-region','top-entity-type':'cloud-region','entity-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'3d567832-df00-49b5-b862-4d3a341dbec1','source-name':'JUNIT','version':'v13','timestamp':'20180515-10:57:55:750'},'entity':{'tenants':{'tenant':[{'vservers':{'vserver':[{'relationship-list':{'relationship':[{'related-to':'pserver','relationship-data':[{'relationship-value':'pserver-1','relationship-key':'pserver.hostname'}],'related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','relationship-label':'tosca.relationships.HostedOn'}]},'l-interfaces':{'l-interface':[{'interface-name':'l-int-1','interface-id':'l-int-1','l3-interface-ipv4-address-list':[{'neutron-network-id':'93fb399c-9bfc-4234-b2bb-a76eda38f117','neutron-subnet-id':'79e5bb69-24bb-4ea3-8d1d-c04fca5f5e1e','l3-interface-ipv4-address':'192.168.70.3'}],'relationship-list':{'relationship':[{'related-to':'pserver','relationship-data':[{'relationship-value':'pserver-1','relationship-key':'pserver.hostname'}],'related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','relationship-label':'tosca.relationships.HostedOn'}]}}]},'vserver-id':'vserver-1'}]},'tenant-id':'tenenat-1'}]},'cloud-owner':'onap-cloud-owner','cloud-region-id':'mtn6'}}"; + + aaiDmaapEventProcessor.process(crWithNestingAndWithRels); + + assertNotEquals("cloud-region collection exists", mongoDatabase().getCollection("cloud-region"), null); + assertTrue("Now pserver has relationship to vserver", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1'" + + "}")) + .iterator().hasNext() + ); + assertTrue("Now pserver has relationship to l-interface", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1'" + + "}")) + .iterator().hasNext() + ); + + + String updatePserverWithoutInterfaceRel = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'UPDATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false,'relationship-list':{'relationship':[{'related-to':'vserver','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'},{'relationship-key':'tenant.tenant-id','relationship-value':'tenenat-1'},{'relationship-key':'vserver.vserver-id','relationship-value':'vserver-1'}]}]}}}"; + + aaiDmaapEventProcessor.process(updatePserverWithoutInterfaceRel); + + assertTrue("Now cloud-region->tenant->vserver should still have relationship to pserver", + mongoDatabase().getCollection("cloud-region") + .find(Document.parse("{" + + "'cloud-owner':'onap-cloud-owner'," + + "'cloud-region-id':'mtn6'," + + "'tenants.tenant.tenant-id':'tenenat-1'," + + "'tenants.tenant.vservers.vserver.vserver-id':'vserver-1'," + + "'tenants.tenant.vservers.vserver.relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("Now cloud-region->tenant->vserver->l-interface should not have relationship to pserver", + mongoDatabase().getCollection("cloud-region") + .find(Document.parse("{" + + "'cloud-owner':'onap-cloud-owner'," + + "'cloud-region-id':'mtn6'," + + "'tenants.tenant.tenant-id':'tenenat-1'," + + "'tenants.tenant.vservers.vserver.vserver-id':'vserver-1'," + + "'tenants.tenant.vservers.vserver.l-interfaces.l-interface.interface-name':'l-int-1'," + + "'tenants.tenant.vservers.vserver.l-interfaces.l-interface.relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1'" + + "}")) + .iterator().hasNext() + ); + } + + @Test + public void createPserverCreateCRWithNestingAndRelationshipsToThenDeletePserverTest() throws Exception { + String pserverCreate = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false}}"; + + aaiDmaapEventProcessor.process(pserverCreate); + assertNotEquals("pserver collection exists", mongoDatabase().getCollection("pserver"), null); + assertEquals("pserver collection contains 1", mongoDatabase().getCollection("pserver").count(), 1); + assertTrue("pserver collection contains the pserver in the event", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("pserver should not have relationship to vserver", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("pserver should not have relationship to l-interface", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1'" + + "}")) + .iterator().hasNext() + ); + + + String crWithNestingAndWithRels = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'cloud-region','top-entity-type':'cloud-region','entity-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'3d567832-df00-49b5-b862-4d3a341dbec1','source-name':'JUNIT','version':'v13','timestamp':'20180515-10:57:55:750'},'entity':{'tenants':{'tenant':[{'vservers':{'vserver':[{'relationship-list':{'relationship':[{'related-to':'pserver','relationship-data':[{'relationship-value':'pserver-1','relationship-key':'pserver.hostname'}],'related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','relationship-label':'tosca.relationships.HostedOn'}]},'l-interfaces':{'l-interface':[{'interface-name':'l-int-1','interface-id':'l-int-1','l3-interface-ipv4-address-list':[{'neutron-network-id':'93fb399c-9bfc-4234-b2bb-a76eda38f117','neutron-subnet-id':'79e5bb69-24bb-4ea3-8d1d-c04fca5f5e1e','l3-interface-ipv4-address':'192.168.70.3'}],'relationship-list':{'relationship':[{'related-to':'pserver','relationship-data':[{'relationship-value':'pserver-1','relationship-key':'pserver.hostname'}],'related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','relationship-label':'tosca.relationships.HostedOn'}]}}]},'vserver-id':'vserver-1'}]},'tenant-id':'tenenat-1'}]},'cloud-owner':'onap-cloud-owner','cloud-region-id':'mtn6'}}"; + + aaiDmaapEventProcessor.process(crWithNestingAndWithRels); + + assertNotEquals("cloud-region collection exists", mongoDatabase().getCollection("cloud-region"), null); + assertTrue("Now pserver has relationship to vserver", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1'" + + "}")) + .iterator().hasNext() + ); + assertTrue("Now pserver has relationship to l-interface", + mongoDatabase().getCollection("pserver") + .find(Document.parse("{" + + "'hostname':'pserver-1'," + + "'relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1'" + + "}")) + .iterator().hasNext() + ); + + String pserverDelete = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'DELETE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false,'relationship-list':{'relationship':[{'related-to':'vserver','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'},{'relationship-key':'tenant.tenant-id','relationship-value':'tenenat-1'},{'relationship-key':'vserver.vserver-id','relationship-value':'vserver-1'}]},{'related-to':'l-interface','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'},{'relationship-key':'tenant.tenant-id','relationship-value':'tenenat-1'},{'relationship-key':'vserver.vserver-id','relationship-value':'vserver-1'},{'relationship-key':'l-interface.interface-name','relationship-value':'l-int-1'}]}]}}}"; + + aaiDmaapEventProcessor.process(pserverDelete); + assertNotEquals("pserver collection exists", mongoDatabase().getCollection("pserver"), null); + assertEquals("pserver collection contains 1", mongoDatabase().getCollection("pserver").count(), 0); + + assertFalse("Now cloud-region->tenant->vserver should not have relationship to pserver", + mongoDatabase().getCollection("cloud-region") + .find(Document.parse("{" + + "'cloud-owner':'onap-cloud-owner'," + + "'cloud-region-id':'mtn6'," + + "'tenants.tenant.tenant-id':'tenenat-1'," + + "'tenants.tenant.vservers.vserver.vserver-id':'vserver-1'," + + "'tenants.tenant.vservers.vserver.relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1'" + + "}")) + .iterator().hasNext() + ); + assertFalse("Now cloud-region->tenant->vserver->l-interface should not have relationship to pserver", + mongoDatabase().getCollection("cloud-region") + .find(Document.parse("{" + + "'cloud-owner':'onap-cloud-owner'," + + "'cloud-region-id':'mtn6'," + + "'tenants.tenant.tenant-id':'tenenat-1'," + + "'tenants.tenant.vservers.vserver.vserver-id':'vserver-1'," + + "'tenants.tenant.vservers.vserver.l-interfaces.l-interface.interface-name':'l-int-1'," + + "'tenants.tenant.vservers.vserver.l-interfaces.l-interface.relationship-list.relationship.related-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1'" + + "}")) + .iterator().hasNext() + ); + + } + + + @Test + public void createPserverRelationshipsToNonExistingTest() throws Exception { + + String pserverWithRelsToNested = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false,'relationship-list':{'relationship':[{'related-to':'cloud-region','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'}]},{'related-to':'vserver','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'},{'relationship-key':'tenant.tenant-id','relationship-value':'tenenat-1'},{'relationship-key':'vserver.vserver-id','relationship-value':'vserver-1'}]},{'related-to':'l-interface','relationship-label':'tosca.relationships.HostedOn','related-link':'/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/mtn6/tenants/tenant/tenenat-1/vservers/vserver/vserver-1/l-interfaces/l-interface/l-int-1','relationship-data':[{'relationship-key':'cloud-region.cloud-owner','relationship-value':'onap-cloud-owner'},{'relationship-key':'cloud-region.cloud-region-id','relationship-value':'mtn6'},{'relationship-key':'tenant.tenant-id','relationship-value':'tenenat-1'},{'relationship-key':'vserver.vserver-id','relationship-value':'vserver-1'},{'relationship-key':'l-interface.interface-name','relationship-value':'l-int-1'}]}]}}}"; + + aaiDmaapEventProcessor.process(pserverWithRelsToNested); + + } + + @Test + public void linterfaceWithLinterfaceTest() throws Exception { + + String linterfaceWithLinterface = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'l-interface','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/c9e8ffb6-a360-4f9c-96c3-f5f0244dfe55-jenkins/lag-interfaces/lag-interface/8806d30d-e5f5-409e-9e9e-9b1c1943058d-jenkins/l-interfaces/l-interface/f4f9b9c7-eb83-4622-9d6f-14027a556ff5-jenkins/l-interfaces/l-interface/89796dd1-89a5-4ddc-bd13-324ba9bce3b6-jenkins','event-type':'AAI-EVENT','domain':'uINT1','action':'DELETE','sequence-number':'0','id':'9060077e-00a3-4239-80ed-855331b4d551','source-name':'FitNesse-Test-jenkins','version':'v13','timestamp':'20180625-01:24:04:857'},'entity':{'pserver-name2':'iqFmGNmNLM6','hostname':'c9e8ffb6-a360-4f9c-96c3-f5f0244dfe55-jenkins','lag-interfaces':{'lag-interface':[{'l-interfaces':{'l-interface':[{'l-interfaces':{'l-interface':[{'v6-wan-link-ip':'PuNFKRUUpd3','interface-name':'89796dd1-89a5-4ddc-bd13-324ba9bce3b6-jenkins','allowed-address-pairs':'RGo6MaADK','prov-status':'uot','macaddr':'xUj8TGre','interface-role':'SyT0hd9Uu4b','selflink':'HxDI','in-maint':false,'admin-status':'GDgD','is-port-mirrored':true,'resource-version':'1529889840462','is-ip-unnumbered':false,'network-name':'RXCo3p3p5BhBS','management-option':'jNiTd','interface-id':'4n8niH','interface-description':'drnTF3'}]},'interface-name':'f4f9b9c7-eb83-4622-9d6f-14027a556ff5-jenkins'}]},'interface-name':'8806d30d-e5f5-409e-9e9e-9b1c1943058d-jenkins'}]}}}"; + + aaiDmaapEventProcessor.process(linterfaceWithLinterface); + + } + + @Test + public void nosTest() throws Exception { + + String nos = getEventPayload("nos"); + + aaiDmaapEventProcessor.process(nos); + + } + + @Test + public void addressListTest() throws Exception { + + String event = getEventPayload("address-list"); + aaiDmaapEventProcessor.process(event); + + } + + @Test + public void vceTest() throws Exception { + + String event = getEventPayload("vce"); + aaiDmaapEventProcessor.process(event); + + } + + @Test + public void largePserverTest() throws Exception { + + String event = getEventPayload("large-pserver"); + aaiDmaapEventProcessor.process(event); + + } + + @Test + public void delRel() throws Exception { + + String event = getEventPayload("deleteRelationship/1-create-logical-link"); + aaiDmaapEventProcessor.process(event); + + event = getEventPayload("deleteRelationship/2-create-generic-vnf"); + aaiDmaapEventProcessor.process(event); + + event = getEventPayload("deleteRelationship/3-create-rel-generic-vnf-vlan-to-logical-link"); + aaiDmaapEventProcessor.process(event); + + event = getEventPayload("deleteRelationship/4-delete-rel-to-generic-vnf-vlan-from-logical-link"); + aaiDmaapEventProcessor.process(event); + + assertFalse("Now generic-vnf->l-interface->vlan should not have relationship to logical-link", + mongoDatabase().getCollection("generic-vnf") + .find(Document.parse("{" + + "'_id': '/network/generic-vnfs/generic-vnf/generic-vnf-id'," + + "'vnf-id': 'generic-vnf-id'," + + "'l-interfaces.l-interface.interface-name': 'l-interface-name-1'," + + "'l-interfaces.l-interface.vlans.vlan.vlan-interface': 'vlan-1'," + + "'l-interfaces.l-interface.vlans.vlan.relationship-list.relationship.related-link':'/aai/v13/network/logical-links/logical-link/logical-link'" + + "}")) + .iterator().hasNext()); + + } + + protected String getEventPayload(String eventpayloadName) throws IOException { + return getPayload("test/payloads/dmaapEvents/" + eventpayloadName + ".json"); + } + + private String getPayload(String filename) throws IOException { + + InputStream inputStream = getClass() + .getClassLoader() + .getResourceAsStream(filename); + + String message = String.format("Unable to find the %s in src/test/resources", filename); + assertNotNull(message, inputStream); + + return IOUtils.toString(inputStream); + } + +}
\ No newline at end of file diff --git a/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessorTest.java b/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessorTest.java new file mode 100644 index 0000000..8fcd7e2 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIDmaapEventProcessorTest.java @@ -0,0 +1,80 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + + +public class AAIDmaapEventProcessorTest { + private AAIDmaapEventProcessor eventProcessor; + + private String validEventMessage = "{'cambria.partition': 'AAI','event-header': {'id': 'ABC','source-name': 'sourceName'},'entity': {'hostname': 'hostName'}}"; + private String invalidEventMessageHeader = "{'cambria.partition': 'AAI','Xevent-header': {'id': 'ABC','source-name': 'sourceName'},'entity': {'hostname': 'hostName'}}"; + private String invalidEventMessageHeaderMissingId = "{'cambria.partition': 'AAI','event-header': {'idX': 'ABC','source-name': 'sourceName'},'entity': {'hostname': 'hostName'}}"; + private String invalidEventMessageHeaderMissingSourceName = "{'cambria.partition': 'AAI','event-header': {'id': 'ABC','source-nameX': 'sourceName'},'entity': {'hostname': 'hostName'}}"; + private String invalidEventMessageBody = "{'cambria.partition': 'AAI','event-header': {'id': 'ABC','source-name': 'sourceName'},'Xentity': {'hostname': 'hostName'}}"; + + + @Before + public void setUp() throws Exception { + eventProcessor = new AAIDmaapEventProcessor(); + } + + @Ignore + @Test + public void testValidEventMessage() throws Exception { + eventProcessor.process(validEventMessage); + JSONObject header = eventProcessor.getEventHeader(); + JSONObject body = eventProcessor.getEventBody(); + assertEquals("header id", "ABC",header.getString("id") ); + assertEquals("hostname", "hostName",body.getString("hostname") ); + } + + @Test(expected = JSONException.class) + public void testJSONException() throws Exception { + eventProcessor.process("invalidJson"); + } + + @Test(expected = JSONException.class) + public void testInvalidHeader() throws Exception { + eventProcessor.process(invalidEventMessageHeader); + } + + @Test(expected = JSONException.class) + public void testInvalidHeaderMissingId() throws Exception { + eventProcessor.process(invalidEventMessageHeaderMissingId); + } + + @Test(expected = JSONException.class) + public void testInvalidHeaderMissingSourceName() throws Exception { + eventProcessor.process(invalidEventMessageHeaderMissingSourceName); + } + + @Test(expected = JSONException.class) + public void testInvalidEventMessageBody() throws Exception { + eventProcessor.process(invalidEventMessageBody); + } +} diff --git a/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIEventConsumerTest.java b/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIEventConsumerTest.java new file mode 100644 index 0000000..3ca3390 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/dmaap/consumer/AAIEventConsumerTest.java @@ -0,0 +1,185 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import com.att.nsa.mr.client.MRConsumer; +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoDatabase; + +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodProcess; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongoCmdOptionsBuilder; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.onap.aai.cacher.common.MongoHelperSingleton; +import org.onap.aai.cacher.egestion.printer.EgestionTestComponent; +import org.onap.aai.cacher.injestion.parser.InjestionTestComponent; +import org.onap.aai.cacher.injestion.parser.PayloadParserService; +import org.onap.aai.cacher.service.helper.RestClientHelperService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +//@Ignore +@RunWith(SpringJUnit4ClassRunner.class) +@Configuration +@ContextConfiguration(classes = {InjestionTestComponent.class, AAIEventConsumerTest.class}) +public class AAIEventConsumerTest { + private static final String DB_NAME = AAIEventConsumerTest.class.getSimpleName(); + private static MongoDatabase mongoDb; + private static RestClientHelperService restClientHelperService; + private static DB db; + private static MongodProcess mongod; + private static MongoClient mongoC; + + private AAIEventConsumer aaiEventConsumer; + + @Autowired + private AAIDmaapEventProcessor aaiDmaapEventProcessor; + + @Bean + public DB db() { + return db; + } + + @Bean + public MongoDatabase mongoDatabase() { + return mongoDb; + } + + @Bean + public RestClientHelperService restClientHelperService() { + return restClientHelperService; + } + + @Bean + public MongoHelperSingleton mongoHelperSingleton(DB db, MongoDatabase mongoDb) { + return new MongoHelperSingleton(db, mongoDb); + } + + @Bean + public AAIDmaapEventProcessor aaiDmaapEventProcessor(MongoHelperSingleton mongoHelperSingleton, PayloadParserService payloadParserService) { + return new AAIDmaapEventProcessor(mongoHelperSingleton, payloadParserService); + } + + + MRConsumer client; + private String validEventMessage = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false}}"; + private String validHeldEventMessage = "{'cambria.partition':'AAI','event-header':{'severity':'NORMAL','entity-type':'pserver','top-entity-type':'pserver','entity-link':'/aai/v13/cloud-infrastructure/pservers/pserver/pserver-1','event-type':'AAI-EVENT','domain':'JUNIT','action':'CREATE','sequence-number':'0','id':'0c3b336d-6554-4ddf-a4d7-90f97876a966','source-name':'JUNIT','version':'v13','timestamp':'20180209-21:02:20:344'},'entity':{'hostname':'pserver-1','in-maint':false}}"; + DmaapConsumerSingleton singleton = DmaapConsumerSingleton.getInstance(); + List<String> eventMessageList = new ArrayList<>(); + + + @BeforeClass + public static void setUp() throws Exception { + String bindIp = "localhost"; + int port = 27017; + startEmbedded(port); + + mongoC = new MongoClient(bindIp, port); + mongoDb = mongoC.getDatabase(DB_NAME); + db = mongoC.getDB(DB_NAME); + + } + + @Before + public void init() throws Exception { + eventMessageList.add(validEventMessage); + //super.setupBundleconfig(); + aaiEventConsumer = new AAIEventConsumer("aaiDmaaPEventConsumer.properties", true); + Properties prop = aaiEventConsumer.getDmaapEventConsumerProperties(); + client = Mockito.mock(MRConsumer.class); + aaiEventConsumer.setConsumer(client); + + + } + + protected static void startEmbedded(int port) throws IOException { + IMongodConfig mongoConfigConfig = new MongodConfigBuilder() + .version(Version.Main.PRODUCTION) + .net(new Net(port, Network.localhostIsIPv6())) + .cmdOptions(new MongoCmdOptionsBuilder().verbose(true).build()) + .configServer(false) + .build(); + + MongodExecutable mongodExecutable = MongodStarter.getDefaultInstance().prepare(mongoConfigConfig); + + mongod = mongodExecutable.start(); + } + + @AfterClass + public static void tearDown() { + if (mongod != null && mongod.isProcessRunning()) { + mongod.stop(); + } + } + + @After + public void cleanup() { + final List<String> collectionNames = new ArrayList<>(); + mongoDb.listCollections().iterator().forEachRemaining(document -> collectionNames.add(document.getString("name"))); + collectionNames.forEach(collectionName -> mongoDb.getCollection(collectionName).drop()); + } + + @Test + public void startProcessing() throws IOException, Exception { + Mockito.when(client.fetch()).thenReturn(eventMessageList); + aaiEventConsumer.startProcessing(aaiDmaapEventProcessor); + } + + @Test + public void startProcessingWaitWithHeldEventMessage() throws IOException, Exception { + singleton.setIsInitialized(true); + singleton.setFirstEventMessage(validHeldEventMessage); + Mockito.when(client.fetch()).thenReturn(eventMessageList); + aaiEventConsumer.startProcessing(aaiDmaapEventProcessor); + } + + @Test + public void startProcessingNoWaitWithHeldEventMessage() throws IOException, Exception { + singleton.setProcessEvents(true); + singleton.setFirstEventMessage(validHeldEventMessage); + Mockito.when(client.fetch()).thenReturn(eventMessageList); + aaiEventConsumer.startProcessing(aaiDmaapEventProcessor); + } + +} + diff --git a/src/test/java/org/onap/aai/cacher/dmaap/consumer/DmaapConsumerSingletonTest.java b/src/test/java/org/onap/aai/cacher/dmaap/consumer/DmaapConsumerSingletonTest.java new file mode 100644 index 0000000..60ee2e1 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/dmaap/consumer/DmaapConsumerSingletonTest.java @@ -0,0 +1,39 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.dmaap.consumer; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class DmaapConsumerSingletonTest { + + static final String firstEventMessage = "firstMessageValue"; + @Test + public void testSingleton() { + DmaapConsumerSingleton dmaapConsumerSingleton = DmaapConsumerSingleton.getInstance(); + dmaapConsumerSingleton.setIsInitialized(true); + dmaapConsumerSingleton.setProcessEvents(false); + dmaapConsumerSingleton.setFirstEventMessage(firstEventMessage); + assertTrue("isInitialized", dmaapConsumerSingleton.getIsInitialized()); + assertFalse("processEvents", dmaapConsumerSingleton.getProcessEvents()); + assertEquals("firstEventMessage", firstEventMessage, dmaapConsumerSingleton.getFirstEventMessage()); + } +} diff --git a/src/test/java/org/onap/aai/cacher/egestion/printer/EgestionTestComponent.java b/src/test/java/org/onap/aai/cacher/egestion/printer/EgestionTestComponent.java new file mode 100644 index 0000000..fa4ce13 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/egestion/printer/EgestionTestComponent.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.egestion.printer; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import java.nio.file.FileSystems; + +@Configuration +@ComponentScan(basePackages = {"org.onap.aai.cacher.egestion.printer"}) +public class EgestionTestComponent { + public EgestionTestComponent() { + System.setProperty("AJSC_HOME", FileSystems.getDefault().getPath(".").toAbsolutePath().toString()); + System.setProperty("BUNDLECONFIG_DIR", "src/main/resources"); + + } +} diff --git a/src/test/java/org/onap/aai/cacher/injestion/parser/AAIResourcesUriTemplatesTest.java b/src/test/java/org/onap/aai/cacher/injestion/parser/AAIResourcesUriTemplatesTest.java new file mode 100644 index 0000000..a48712f --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/injestion/parser/AAIResourcesUriTemplatesTest.java @@ -0,0 +1,137 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = InjestionTestComponent.class) +public class AAIResourcesUriTemplatesTest { + + @Autowired + AAIResourcesUriTemplates aaiResourcesUriTemplates; + + @Test + public void getUriTemplateByType() throws Exception { + + assertEquals("Service template is returned", + "/service-design-and-creation/services/service/{service-id}", + aaiResourcesUriTemplates.getUriTemplateByType("service")); + + assertFalse(aaiResourcesUriTemplates.getUriTemplateByType("does not exist") != null); + + } + + @Test + public void getMatchingStartingTemplate() throws Exception { + String uri = "/service-design-and-creation/services/service/id/l-interfaces/l-interface/name/p-interfaces/p-interface/name2"; + assertEquals("Service template is returned", + "/service-design-and-creation/services/service/{service-id}", + aaiResourcesUriTemplates.getMatchingStartingTemplate(uri).get()); + + uri = "/l-interfaces/l-interface/name/p-interfaces/p-interface/name2"; + assertEquals("l-interface template is returned", + "/l-interfaces/l-interface/{interface-name}", + aaiResourcesUriTemplates.getMatchingStartingTemplate(uri).get()); + + uri = "/l-interface/name/p-interfaces/p-interface/name2"; + assertFalse(aaiResourcesUriTemplates.getMatchingStartingTemplate(uri).isPresent()); + } + + @Test + public void uriToTemplatesValidTest() throws Exception { + String uri = "/service-design-and-creation/services/service/id/l-interfaces/l-interface/name/p-interfaces/p-interface/name2"; + List<String> expected = Arrays.asList( + "/service-design-and-creation/services/service/{service-id}", + "/l-interfaces/l-interface/{interface-name}", + "/p-interfaces/p-interface/{interface-name}" + ); + + assertThat(aaiResourcesUriTemplates.uriToTemplates(uri), is(expected)); + } + + @Test + public void uriToTemplatesRepeatedValidTest() throws Exception { + String uri = "/service-design-and-creation/services/service/id/l-interfaces/l-interface/name/l-interfaces/l-interface/name2"; + List<String> expected = Arrays.asList( + "/service-design-and-creation/services/service/{service-id}", + "/l-interfaces/l-interface/{interface-name}", + "/l-interfaces/l-interface/{interface-name}" + ); + + assertThat(aaiResourcesUriTemplates.uriToTemplates(uri), is(expected)); + } + + @Test + public void uriToSegmentsValidTest() throws Exception { + String uri = "/service-design-and-creation/services/service/id/l-interfaces/l-interface/name/p-interfaces/p-interface/name2"; + List<String> expected = Arrays.asList( + "/service-design-and-creation/services/service/id", + "/l-interfaces/l-interface/name", + "/p-interfaces/p-interface/name2" + ); + + assertThat(aaiResourcesUriTemplates.uriToSegments(uri), is(expected)); + } + + @Test + public void uriAndTemplateToKeyValueMappingTest() throws Exception { + String uri = "/service-design-and-creation/services/service/id"; + String template = "/service-design-and-creation/services/service/{service-id}"; + Map<String, String> expected = new HashMap<>(); + expected.put("service-id", "id"); + + assertThat(aaiResourcesUriTemplates.getUriTemplateMappings(uri, template), is(expected)); + } + + @Test + public void uriAndTemplateToKeyValueMappingWithEncodingTest() throws Exception { + String uri = "/service-design-and-creation/services/service/i%3Ad"; + String template = "/service-design-and-creation/services/service/{service-id}"; + Map<String, String> expected = new HashMap<>(); + expected.put("service-id", "i:d"); + + assertThat(aaiResourcesUriTemplates.getUriTemplateMappings(uri, template), is(expected)); + } + + @Test + public void uriAndTemplateToKeyValueMappingWihtMultipleTest() throws Exception { + String uri = "/cloud-infrastructure/cloud-regions/cloud-region/owner/i%3Ad"; + String template = "/cloud-infrastructure/cloud-regions/cloud-region/{cloud-owner}/{cloud-region-id}"; + Map<String, String> expected = new HashMap<>(); + expected.put("cloud-owner", "owner"); + expected.put("cloud-region-id", "i:d"); + + assertThat(aaiResourcesUriTemplates.getUriTemplateMappings(uri, template), is(expected)); + } + +}
\ No newline at end of file diff --git a/src/test/java/org/onap/aai/cacher/injestion/parser/InjestionTestComponent.java b/src/test/java/org/onap/aai/cacher/injestion/parser/InjestionTestComponent.java new file mode 100644 index 0000000..34cc8a3 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/injestion/parser/InjestionTestComponent.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import java.nio.file.FileSystems; + +@Configuration +@ComponentScan(basePackages = {"org.onap.aai.cacher.injestion"}) +public class InjestionTestComponent { + public InjestionTestComponent() { + System.setProperty("AJSC_HOME", FileSystems.getDefault().getPath(".").toAbsolutePath().toString()); + System.setProperty("BUNDLECONFIG_DIR", "src/main/resources"); + + } +} diff --git a/src/test/java/org/onap/aai/cacher/injestion/parser/PayloadParserServiceTest.java b/src/test/java/org/onap/aai/cacher/injestion/parser/PayloadParserServiceTest.java new file mode 100644 index 0000000..1579323 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/injestion/parser/PayloadParserServiceTest.java @@ -0,0 +1,148 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aai.cacher.injestion.parser.strategy.PayloadParserType; +import org.onap.aai.cacher.model.CacheEntry; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = InjestionTestComponent.class) +public class PayloadParserServiceTest { + + @Autowired + private PayloadParserService parserService; + + private JsonParser parser = new JsonParser(); + + private String aaiGetAllServiceResponse = + "{" + + " 'service': [" + + " {" + + " 'service-id': 'service-id-1:1'," + + " 'service-description': 'A'," + + " 'resource-version': '1'" + + " }," + + " {" + + " 'service-id': 'service-id-2'," + + " 'service-description': 'B'," + + " 'resource-version': '2'" + + " }" + + " ]" + + "}"; + private JsonObject aaiGetAllServiceResponseJson = parser.parse(aaiGetAllServiceResponse).getAsJsonObject(); + + + + private void print(List<CacheEntry> result) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + result.forEach(e -> System.out.println("Collection: " + e.getCollection() + "\nKey: " + e.getId() + "\n" + gson.toJson(e.getPayload()))); + } + + @Test + public void testGetAllAAIResourceTest() throws JSONException { + String expectedUri = "/service-design-and-creation/services/service/service-id-1%3A1"; + + List<CacheEntry> result = parserService.doParse("service", aaiGetAllServiceResponseJson, "aai-resource-get-all"); + print(result); + + assertTrue(result.stream().map(cacheIdentifier -> cacheIdentifier.getId()).anyMatch(id -> id.equals(expectedUri))); + JSONAssert.assertEquals( + new JSONObject(aaiGetAllServiceResponseJson.getAsJsonArray("service").get(0).getAsJsonObject().toString()), + new JSONObject(result.stream().filter(e -> e.getId().equals(expectedUri)).map(CacheEntry::getPayload).findFirst().get().toString()), + false); + + } + + @Test + public void testGetAllAAIResourceStringTest() throws JSONException { + String expectedUri = "/service-design-and-creation/services/service/service-id-2"; + + List<CacheEntry> result = parserService.doParse("service", aaiGetAllServiceResponse, PayloadParserType.AAI_RESOURCE_GET_ALL); + print(result); + + assertTrue(result.stream().map(cacheIdentifier -> cacheIdentifier.getId()).anyMatch(id -> id.equals(expectedUri))); + JSONAssert.assertEquals( + new JSONObject(aaiGetAllServiceResponseJson.getAsJsonArray("service").get(1).getAsJsonObject().toString()), + new JSONObject(result.stream().filter(e -> e.getId().equals(expectedUri)).map(CacheEntry::getPayload).findFirst().get().toString()), + false); + } + + @Test + public void testNoneStrategyTest1() throws JSONException { + String cacheKey = "service"; + List<CacheEntry> result = parserService.doParse(cacheKey, aaiGetAllServiceResponse); + print(result); + noneTests(cacheKey, result); + } + + @Test + public void testNoneStrategyTest2() throws JSONException { + String cacheKey = "service"; + List<CacheEntry> result = parserService.doParse(cacheKey, aaiGetAllServiceResponseJson); + print(result); + noneTests(cacheKey, result); + } + + @Test + public void testNoneStrategyTest3() throws JSONException { + String cacheKey = "service"; + List<CacheEntry> result = parserService.doParse(cacheKey, aaiGetAllServiceResponse, PayloadParserType.NONE); + print(result); + noneTests(cacheKey, result); + } + + @Test + public void testNoneStrategyTest4() throws JSONException { + String cacheKey = "service"; + List<CacheEntry> result = parserService.doParse(cacheKey, aaiGetAllServiceResponse, "none"); + print(result); + noneTests(cacheKey, result); + } + + private void noneTests(String cacheKey, List<CacheEntry> result) throws JSONException { + assertThat(result.size(), is(1)); + assertTrue(result.stream().map(cacheIdentifier -> cacheIdentifier.getId()).anyMatch(id -> id.equals(cacheKey))); + JSONAssert.assertEquals( + new JSONObject(aaiGetAllServiceResponse), + new JSONObject(result.get(0).getPayload().toString()), + false); + } + + +} + diff --git a/src/test/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategyTest.java b/src/test/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategyTest.java new file mode 100644 index 0000000..8a4ab0b --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategyTest.java @@ -0,0 +1,429 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser.strategy; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aai.cacher.injestion.parser.InjestionTestComponent; +import org.onap.aai.cacher.injestion.parser.PayloadParserService; +import org.onap.aai.cacher.model.CacheEntry; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.MultiValueMap; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = InjestionTestComponent.class) +public class AAIResourceDmaapParserStrategyTest { + + @Autowired + private PayloadParserService parserService; + + @Autowired + @Qualifier("aai-resource-dmaap") + private AAIResourceDmaapParserStrategy aaiResourceDmaapParserStrategy; + + private JsonParser parser = new JsonParser(); + + private JsonObject pserverCreateEvent = parser.parse( + new FileReader("./src/test/resources/test/payloads/dmaap-pserver-create.json")).getAsJsonObject(); + + public AAIResourceDmaapParserStrategyTest() throws FileNotFoundException {} + + private void print(List<CacheEntry> result) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + result.forEach(e -> System.out.println("\n\nCollection: " + e.getCollection() + + "\nKey: " + e.getId() + + "\nFind: " + gson.toJson(e.getFindQuery()) + + "\nNestedFind: " + gson.toJson(e.getNestedFind()) + + "\nNestedField: " + e.getNestedField() + + "\nNestedFieldIdentifier: " + gson.toJson(e.getNestedFieldIdentifierObj()) + + "\nPayload: " + gson.toJson(e.getPayload()))); + } + + @Test + public void test(){ + List<CacheEntry> result = parserService.doParse("dmaapEvent", pserverCreateEvent, PayloadParserType.AAI_RESOURCE_DMAAP); + print(result); + } + + + @Test + public void getUriTest() { + String fullUri = aaiResourceDmaapParserStrategy.getFullUri(pserverCreateEvent.getAsJsonObject("event-header")); + assertEquals("/aai/v12/cloud-infrastructure/pservers/pserver/dmaap-pserver-create", fullUri); + String uri = aaiResourceDmaapParserStrategy.getUri(fullUri); + assertEquals("/cloud-infrastructure/pservers/pserver/dmaap-pserver-create", uri); + } + + @Test + public void getAaiUriSegmentsTest() { + + String uri = "/service-design-and-creation/services/service/id/l-interfaces/l-interface/name/p-interfaces/p-interface/name2"; + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + + assertEquals("3 segments are generated", 3, segments.size()); + + assertEquals("Segment 1 plural is services", "services", segments.get(0).getSegmentPlural().get()); + assertEquals("Segment 2 plural is l-interfaces", "l-interfaces", segments.get(1).getSegmentPlural().get()); + assertEquals("Segment 3 plural is p-interfaces", "p-interfaces", segments.get(2).getSegmentPlural().get()); + + assertEquals("Segment 1 singular is service", "service", segments.get(0).getSegmentSingular()); + assertEquals("Segment 2 singular is l-interface", "l-interface", segments.get(1).getSegmentSingular()); + assertEquals("Segment 3 singular is p-interface", "p-interface", segments.get(2).getSegmentSingular()); + + assertEquals("Segment 1 template", + "/service-design-and-creation/services/service/{service-id}", + segments.get(0).getSegmentTemplate()); + assertEquals("Segment 2 template", + "/l-interfaces/l-interface/{interface-name}", + segments.get(1).getSegmentTemplate()); + assertEquals("Segment 3 template", + "/p-interfaces/p-interface/{interface-name}", + segments.get(2).getSegmentTemplate()); + + assertEquals("Segment 1 uri", + "/service-design-and-creation/services/service/id", + segments.get(0).getSegment()); + assertEquals("Segment 2 uri", + "/l-interfaces/l-interface/name", + segments.get(1).getSegment()); + assertEquals("Segment 3 uri", + "/p-interfaces/p-interface/name2", + segments.get(2).getSegment()); + + Map<String, String> expected = new HashMap<>(); + expected.put("service-id", "id"); + assertEquals("Segment 1 mapping", expected, segments.get(0).getSegmentKeyValues()); + expected = new HashMap<>(); + expected.put("interface-name", "name"); + assertEquals("Segment 2 mapping", expected, segments.get(1).getSegmentKeyValues()); + expected = new HashMap<>(); + expected.put("interface-name", "name2"); + assertEquals("Segment 3 mapping", expected, segments.get(2).getSegmentKeyValues()); + } + + @Test + public void getEntityBodyChildTest() throws Exception { + String uri = "/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/ams1b/tenants/tenant/52fd05137ab4453bb53084a13c7bb7a4/vservers/vserver/vs-id"; + String entityString = + "{" + + " 'tenants':" + + " {" + + " 'tenant': [" + + " {" + + " 'vservers':" + + " {" + + " 'vserver': [" + + " {" + + " 'in-maint': false," + + " 'resource-version': '1525978690717'," + + " 'vserver-name': 'slaa-regression-cr-id-api-server-449704329'," + + " 'vserver-id': 'vs-id'" + + " }" + + " ]" + + " }," + + " 'tenant-id': 'ten-id'," + + " 'tenant-name': 'name'" + + " }" + + " ]" + + " }," + + " 'cloud-owner': 'cr-o'," + + " 'owner-defined-type': 'lcp'," + + " 'cloud-region-id': 'cr-id'" + + "}"; + + JsonObject entity = parser.parse(entityString).getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + + JsonObject result = aaiResourceDmaapParserStrategy.getEntityBody(entity, segments); + + JSONAssert.assertEquals( + new JSONObject(entity + .getAsJsonObject("tenants").getAsJsonArray("tenant").get(0) .getAsJsonObject() + .getAsJsonObject("vservers").getAsJsonArray("vserver").get(0).getAsJsonObject() + .toString()), + new JSONObject(result.toString()), + true); + + } + + @Test + public void getEntityBodyTopTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn"; + String entityString = "{'hostname':'hn','in-maint':false,'resource-version':'1525801811662','pserver-id':'0A47B945-9C74-4CBE-AD72-0DECB966EB94'}"; + + JsonObject entity = parser.parse(entityString).getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + + JsonObject result = aaiResourceDmaapParserStrategy.getEntityBody(entity, segments); + + JSONAssert.assertEquals( + new JSONObject(entity.toString()), + new JSONObject(result.toString()), + true); + + } + + @Test + public void getFindQueryTopTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn"; + JsonObject expected = parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/hn'," + + "'hostname':'hn'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject findQuery = aaiResourceDmaapParserStrategy.getFindQuery(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(findQuery.toString()), + true); + } + + @Test + public void getFindQueryOneLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1"; + JsonObject expected = parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/hn'," + + "'hostname':'hn'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject findQuery = aaiResourceDmaapParserStrategy.getFindQuery(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(findQuery.toString()), + true); + } + + @Test + public void getFindQueryTwoLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1/l-interfaces/l-interface/interface-2"; + JsonObject expected = parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/hn'," + + "'hostname':'hn'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject findQuery = aaiResourceDmaapParserStrategy.getFindQuery(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(findQuery.toString()), + true); + } + + @Test + public void getNestedFindQueryTopTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn"; + JsonObject expected = parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/hn'," + + "'hostname':'hn'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject findQuery = aaiResourceDmaapParserStrategy.getNestedFindQuery(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(findQuery.toString()), + true); + } + + @Test + public void getNestedFindQueryOneLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1"; + JsonObject expected = parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/hn'," + + "'hostname':'hn'," + + "'p-interfaces.p-interface.interface-name':'interface-1'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject findQuery = aaiResourceDmaapParserStrategy.getNestedFindQuery(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(findQuery.toString()), + true); + } + + @Test + public void getNestedFindQueryTwoLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1/l-interfaces/l-interface/interface-2"; + JsonObject expected = parser.parse("{'_id':'/cloud-infrastructure/pservers/pserver/hn'," + + "'hostname':'hn'," + + "'p-interfaces.p-interface.interface-name':'interface-1'," + + "'p-interfaces.p-interface.l-interfaces.l-interface.interface-name':'interface-2'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject findQuery = aaiResourceDmaapParserStrategy.getNestedFindQuery(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(findQuery.toString()), + true); + } + + @Test + public void getNestedFieldTopTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn"; + String expected = ""; + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + String nestedField = aaiResourceDmaapParserStrategy.getNestedField(segments); + + assertEquals("Top nested field", expected, nestedField); + } + + @Test + public void getNestedFieldOneLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1"; + String expected = "p-interfaces.p-interface"; + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + String nestedField = aaiResourceDmaapParserStrategy.getNestedField(segments); + + assertEquals("Top nested field", expected, nestedField); + } + + @Test + public void getNestedFieldTwoLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1/l-interfaces/l-interface/interface-2"; + String expected = "p-interfaces.p-interface.$.l-interfaces.l-interface"; + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + String nestedField = aaiResourceDmaapParserStrategy.getNestedField(segments); + + assertEquals("Top nested field", expected, nestedField); + } + + @Test + public void getNestedFieldThreeLevelOddCaseTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1/l-interfaces/l-interface/interface-2/l3-interface-ipv4-address-list/addressA"; + String expected = "p-interfaces.p-interface.$.l-interfaces.l-interface.$.l3-interface-ipv4-address-list"; + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + String nestedField = aaiResourceDmaapParserStrategy.getNestedField(segments); + + assertEquals("Top nested field", expected, nestedField); + } + + + + + @Test + public void getNestedIdentifierTopTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn"; + JsonObject expected = parser.parse("{}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject nestedIdentifier = aaiResourceDmaapParserStrategy.getNestedIdentifier(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(nestedIdentifier.toString()), + true); + } + + @Test + public void getNestedIdentifierOneLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1"; + JsonObject expected = parser.parse("{'interface-name':'interface-1'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject nestedIdentifier = aaiResourceDmaapParserStrategy.getNestedIdentifier(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(nestedIdentifier.toString()), + true); + } + + @Test + public void getNestedIdentifierTwoLevelTest() throws Exception { + String uri = "/cloud-infrastructure/pservers/pserver/hn/p-interfaces/p-interface/interface-1/l-interfaces/l-interface/interface-2"; + JsonObject expected = parser.parse("{'interface-name':'interface-2'}").getAsJsonObject(); + + List<AAIResourceDmaapParserStrategy.AAIUriSegment> segments = aaiResourceDmaapParserStrategy.getAaiUriSegments(uri); + JsonObject nestedIdentifier = aaiResourceDmaapParserStrategy.getNestedIdentifier(segments); + + JSONAssert.assertEquals( + new JSONObject(expected.toString()), + new JSONObject(nestedIdentifier.toString()), + true); + } + + + @Test + public void getFullUriPrefixTest() throws Exception { + assertEquals("/aai/v12", aaiResourceDmaapParserStrategy.getFullUriPrefix("/aai/v12/network/pnfs/pnf/pnf-name-value/p-interfaces/p-interface/xe-10%2F3%2F2/l-interfaces/l-interface/l-interface-name")); + assertEquals("/aai/v4", aaiResourceDmaapParserStrategy.getFullUriPrefix("/aai/v4/names")); + } + + + @Test + public void fullUriToRelationshipObj() throws Exception { + String fullUri = AAIResourceDmaapParserStrategyTestConstants.VSERVER_URI; + String expectedRelObj = AAIResourceDmaapParserStrategyTestConstants.VSERVER_RELATIONSHIP_OBJ; + JsonObject relObj = aaiResourceDmaapParserStrategy.fullUriToRelationshipObj(fullUri, "tosca.relationships.HostedOn"); + + JSONAssert.assertEquals(new JSONObject(expectedRelObj), new JSONObject(relObj.toString()), true); + } + + @Test + public void verifyRelationshipEntriesOnUpdateTest() throws Exception { + List<CacheEntry> result = aaiResourceDmaapParserStrategy + .process("TEST", parser.parse(AAIResourceDmaapParserStrategyTestConstants.GENERIC_VNF_EVENT_WITH_2_RELAT).getAsJsonObject()); + + assertEquals(3, result.size()); + + } + @Test + public void verifyRelationshipEntriesSimpleEvent() throws Exception { + List<CacheEntry> result = aaiResourceDmaapParserStrategy + .process("TEST", parser.parse(AAIResourceDmaapParserStrategyTestConstants.GENERIC_VNF_EVENT).getAsJsonObject()); + + assertEquals(1, result.size()); + + } + + @Test + public void getFromRelationshipFullUriToRelationshipObjTest() throws Exception { + String entity = AAIResourceDmaapParserStrategyTestConstants.FULL_PSERVER; + String fullUri = AAIResourceDmaapParserStrategyTestConstants.FULL_PSERVER_URI; + MultiValueMap<String, AAIResourceDmaapParserStrategy.AAIRelatedToDetails> result = aaiResourceDmaapParserStrategy.getFromRelationshipFullUriToRelationshipObj(parser.parse(entity).getAsJsonObject(), fullUri); + + assertEquals(3, result.size()); + + } +}
\ No newline at end of file diff --git a/src/test/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategyTestConstants.java b/src/test/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategyTestConstants.java new file mode 100644 index 0000000..659c881 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/injestion/parser/strategy/AAIResourceDmaapParserStrategyTestConstants.java @@ -0,0 +1,372 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.injestion.parser.strategy; + +public class AAIResourceDmaapParserStrategyTestConstants { + + public static final String VSERVER_URI = "/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/SERVERNAME%3A%3AXXXX/vservers/vserver/afce2113-297a-436c-811a-acf9981fff68"; + public static final String VSERVER_RELATIONSHIP_OBJ = "{" + + " 'related-to': 'vserver'," + + " 'relationship-label': 'tosca.relationships.HostedOn'," + + " 'related-link': '/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/SERVERNAME%3A%3AXXXX/vservers/vserver/afce2113-297a-436c-811a-acf9981fff68'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'cloud-region.cloud-owner'," + + " 'relationship-value': 'onap-cloud-owner'" + + " }," + + " {" + + " 'relationship-key': 'cloud-region.cloud-region-id'," + + " 'relationship-value': 'AAIAIC25'" + + " }," + + " {" + + " 'relationship-key': 'tenant.tenant-id'," + + " 'relationship-value': 'SERVERNAME::XXXX'" + + " }," + + " {" + + " 'relationship-key': 'vserver.vserver-id'," + + " 'relationship-value': 'afce2113-297a-436c-811a-acf9981fff68'" + + " }" + + " ]" + + "}"; + + public static final String FULL_PSERVER_URI = "/aai/v12/cloud-infrastructure/pservers/pserver/SERVERNAME"; + public static final String FULL_PSERVER = "{" + + " 'hostname': 'SERVERNAME'," + + " 'relationship-list':" + + " {" + + " 'relationship': [" + + " {" + + " 'related-to': 'generic-vnf'," + + " 'relationship-label': 'tosca.relationships.HostedOn'," + + " 'related-link': '/aai/v12/network/generic-vnfs/generic-vnf/205c64eb-88b1-490a-a838-b0080e6902bc'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'generic-vnf.vnf-id'," + + " 'relationship-value': '205c64eb-88b1-490a-a838-b0080e6902bc'" + + " }" + + " ]," + + " 'related-to-property': [" + + " {" + + " 'property-key': 'generic-vnf.vnf-name'," + + " 'property-value': 'USAUTOUFTIL2001UJDM02'" + + " }" + + " ]" + + " }," + + " {" + + " 'related-to': 'vserver'," + + " 'relationship-label': 'tosca.relationships.HostedOn'," + + " 'related-link': '/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/SERVERNAME%3A%3AXXXX/vservers/vserver/74a47c2c-b53f-4264-87fc-bb85c7f49207'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'cloud-region.cloud-owner'," + + " 'relationship-value': 'onap-cloud-owner'" + + " }," + + " {" + + " 'relationship-key': 'cloud-region.cloud-region-id'," + + " 'relationship-value': 'AAIAIC25'" + + " }," + + " {" + + " 'relationship-key': 'tenant.tenant-id'," + + " 'relationship-value': 'SERVERNAME::XXXX'" + + " }," + + " {" + + " 'relationship-key': 'vserver.vserver-id'," + + " 'relationship-value': '74a47c2c-b53f-4264-87fc-bb85c7f49207'" + + " }" + + " ]," + + " 'related-to-property': [" + + " {" + + " 'property-key': 'vserver.vserver-name'," + + " 'property-value': 'SERVERNAME-USAUTOUFTIL2001UJTE03'" + + " }" + + " ]" + + " }," + + " {" + + " 'related-to': 'vserver'," + + " 'relationship-label': 'tosca.relationships.HostedOn'," + + " 'related-link': '/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/SERVERNAME%3A%3AXXXX/vservers/vserver/afce2113-297a-436c-811a-acf9981fff68'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'cloud-region.cloud-owner'," + + " 'relationship-value': 'onap-cloud-owner'" + + " }," + + " {" + + " 'relationship-key': 'cloud-region.cloud-region-id'," + + " 'relationship-value': 'AAIAIC25'" + + " }," + + " {" + + " 'relationship-key': 'tenant.tenant-id'," + + " 'relationship-value': 'SERVERNAME::XXXX'" + + " }," + + " {" + + " 'relationship-key': 'vserver.vserver-id'," + + " 'relationship-value': 'afce2113-297a-436c-811a-acf9981fff68'" + + " }" + + " ]," + + " 'related-to-property': [" + + " {" + + " 'property-key': 'vserver.vserver-name'," + + " 'property-value': 'SERVERNAME-vjunos0'" + + " }" + + " ]" + + " }," + + " {" + + " 'related-to': 'complex'," + + " 'relationship-label': 'org.onap.relationships.inventory.LocatedIn'," + + " 'related-link': '/aai/v12/cloud-infrastructure/complexes/complex/STLSMO0914'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'complex.physical-location-id'," + + " 'relationship-value': 'STLSMO0914'" + + " }" + + " ]" + + " }" + + " ]" + + " }," + + " 'p-interfaces':" + + " {" + + " 'p-interface': [" + + " {" + + " 'interface-name': 'ge-0/0/10'," + + " 'relationship-list':" + + " {" + + " 'relationship': [" + + " {" + + " 'related-to': 'physical-link'," + + " 'relationship-label': 'tosca.relationships.network.LinksTo'," + + " 'related-link': '/aai/v12/network/physical-links/physical-link/HIS.1702.03053.121'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'physical-link.link-name'," + + " 'relationship-value': 'HIS.1702.03053.121'" + + " }" + + " ]" + + " }" + + " ]" + + " }" + + " }," + + " {" + + " 'interface-name': 'ge-0/0/11'," + + " 'relationship-list':" + + " {" + + " 'relationship': [" + + " {" + + " 'related-to': 'physical-link'," + + " 'relationship-label': 'tosca.relationships.network.LinksTo'," + + " 'related-link': '/aai/v12/network/physical-links/physical-link/HIS.1702.03053.122'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'physical-link.link-name'," + + " 'relationship-value': 'HIS.1702.03053.122'" + + " }" + + " ]" + + " }" + + " ]" + + " }" + + " }" + + " ]" + + " }" + + "}"; + + + public final static String GENERIC_VNF_EVENT_WITH_2_RELAT = "{" + + " 'cambria.partition': 'AAI'," + + " 'event-header':" + + " {" + + " 'severity': 'NORMAL'," + + " 'entity-type': 'generic-vnf'," + + " 'top-entity-type': 'generic-vnf'," + + " 'entity-link': '/aai/v13/network/generic-vnfs/generic-vnf/cc1703a9-a63f-46c5-a6b1-7ff67f3a9848'," + + " 'event-type': 'AAI-EVENT'," + + " 'domain': 'e2e1'," + + " 'action': 'UPDATE'," + + " 'sequence-number': '0'," + + " 'id': '35717064-c145-4172-941a-ae71dced750e'," + + " 'version': 'v12'," + + " 'timestamp': '20180523-15:41:19:570'" + + " }," + + " 'entity':" + + " {" + + " 'vnf-id': 'cc1703a9-a63f-46c5-a6b1-7ff67f3a9848'," + + " 'vf-modules':" + + " {" + + " 'vf-module': [" + + " {" + + " 'vf-module-id': 'eb792c93-d7e6-481c-8a78-e63d39f63e3a'" + + " }," + + " {" + + " 'vf-module-id': '43448d88-099f-4a33-8860-889773440675'" + + " }" + + " ]" + + " }," + + " 'relationship-list':" + + " {" + + " 'relationship': [" + + " {" + + " 'related-to': 'service-instance'," + + " 'relationship-label': 'org.onap.relationships.inventory.ComposedOf'," + + " 'related-link': '/aai/v13/business/customers/customer/1702_IT3_SubscGblID_20170426162928/service-subscriptions/service-subscription/XXXX-VMS/service-instances/service-instance/SERVERNAME'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'customer.global-customer-id'," + + " 'relationship-value': '1702_IT3_SubscGblID_20170426162928'" + + " }," + + " {" + + " 'relationship-key': 'service-subscription.service-type'," + + " 'relationship-value': 'XXXX-VMS'" + + " }," + + " {" + + " 'relationship-key': 'service-instance.service-instance-id'," + + " 'relationship-value': 'SERVERNAME'" + + " }" + + " ]," + + " 'related-to-property': [" + + " {" + + " 'property-key': 'service-instance.service-instance-name'" + + " }" + + " ]" + + " }," + + " {" + + " 'related-to': 'vserver'," + + " 'relationship-label': 'tosca.relationships.HostedOn'," + + " 'related-link': '/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/SERVERNAME%3A%3AXXXX-VMS/vservers/vserver/e77451f2-1c07-4db4-b92b-9907b840fc8f'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'cloud-region.cloud-owner'," + + " 'relationship-value': 'onap-cloud-owner'" + + " }," + + " {" + + " 'relationship-key': 'cloud-region.cloud-region-id'," + + " 'relationship-value': 'AAIAIC25'" + + " }," + + " {" + + " 'relationship-key': 'tenant.tenant-id'," + + " 'relationship-value': 'SERVERNAME::XXXX-VMS'" + + " }," + + " {" + + " 'relationship-key': 'vserver.vserver-id'," + + " 'relationship-value': 'e77451f2-1c07-4db4-b92b-9907b840fc8f'" + + " }" + + " ]," + + " 'related-to-property': [" + + " {" + + " 'property-key': 'vserver.vserver-name'," + + " 'property-value': 'SERVERNAME-vsrx'" + + " }" + + " ]" + + " }" + + " ]" + + " }" + + " }," + + " 'existing-obj':" + + " {" + + " 'vnf-id': 'cc1703a9-a63f-46c5-a6b1-7ff67f3a9848'," + + " 'vf-modules':" + + " {" + + " 'vf-module': [" + + " {" + + " 'vf-module-id': 'eb792c93-d7e6-481c-8a78-e63d39f63e3a'" + + " }," + + " {" + + " 'vf-module-id': '43448d88-099f-4a33-8860-889773440675'," + + " 'relationship-list':" + + " {" + + " 'relationship': [" + + " {" + + " 'related-to': 'l3-network'," + + " 'relationship-data': [" + + " {" + + " 'relationship-value': '91eae07d-6f38-4fd8-b929-e7c04614c8c3'," + + " 'relationship-key': 'l3-network.network-id'" + + " }" + + " ]," + + " 'related-link': '/aai/v13/network/l3-networks/l3-network/91eae07d-6f38-4fd8-b929-e7c04614c8c3'," + + " 'relationship-label': 'org.onap.relationships.inventory.Uses'," + + " 'related-to-property': [" + + " {" + + " 'property-key': 'l3-network.network-name'," + + " 'property-value': 'ADIODvPE-24388-T-E2E-001_int_AdiodVpeTenantOamNetwork.vpeNodMisOam_net_2'" + + " }" + + " ]" + + " }" + + " ]" + + " }" + + " }" + + " ]" + + " }," + + " 'relationship-list':" + + " {" + + " 'relationship': [" + + " {" + + " 'related-to': 'vserver'," + + " 'relationship-label': 'tosca.relationships.HostedOn'," + + " 'related-link': '/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/SERVERNAME%3A%3AXXXX-VMS/vservers/vserver/e77451f2-1c07-4db4-b92b-9907b840fc8f'," + + " 'relationship-data': [" + + " {" + + " 'relationship-key': 'cloud-region.cloud-owner'," + + " 'relationship-value': 'onap-cloud-owner'" + + " }," + + " {" + + " 'relationship-key': 'cloud-region.cloud-region-id'," + + " 'relationship-value': 'AAIAIC25'" + + " }," + + " {" + + " 'relationship-key': 'tenant.tenant-id'," + + " 'relationship-value': 'SERVERNAME::XXXX-VMS'" + + " }," + + " {" + + " 'relationship-key': 'vserver.vserver-id'," + + " 'relationship-value': 'e77451f2-1c07-4db4-b92b-9907b840fc8f'" + + " }" + + " ]," + + " 'related-to-property': [" + + " {" + + " 'property-key': 'vserver.vserver-name'," + + " 'property-value': 'SERVERNAME-vsrx'" + + " }" + + " ]" + + " }" + + " ]" + + " }" + + " }" + + "}"; + + public final static String GENERIC_VNF_EVENT = "{" + + " 'cambria.partition': 'AAI'," + + " 'event-header':" + + " {" + + " 'severity': 'NORMAL'," + + " 'entity-type': 'generic-vnf'," + + " 'top-entity-type': 'generic-vnf'," + + " 'entity-link': '/aai/v13/network/generic-vnfs/generic-vnf/cc1703a9-a63f-46c5-a6b1-7ff67f3a9848'," + + " 'event-type': 'AAI-EVENT'," + + " 'domain': 'e2e1'," + + " 'action': 'UPDATE'," + + " 'sequence-number': '0'," + + " 'id': '35717064-c145-4172-941a-ae71dced750e'," + + " 'version': 'v12'," + + " 'timestamp': '20180523-15:41:19:570'" + + " }," + + " 'entity':" + + " {" + + " 'vnf-id': 'cc1703a9-a63f-46c5-a6b1-7ff67f3a9848'" + + " }" + + "}"; +} diff --git a/src/test/java/org/onap/aai/cacher/model/CacheKeyTest.java b/src/test/java/org/onap/aai/cacher/model/CacheKeyTest.java new file mode 100644 index 0000000..19a3b3b --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/model/CacheKeyTest.java @@ -0,0 +1,169 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.model; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class CacheKeyTest { + + public String inputGETOnInit = "{" + + "'cacheKey': 'cloud-region'," + + "'baseUrl': 'http://localhost:8447'," + + "'module': '/aai/v13/'," + + "'URI': 'cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3'," + + "'timingIndicator': 'onInit'," + + "'httpMethod': 'GET'}"; + + public String inputGETFirstHitDefault = "{" + + "'cacheKey': 'cloud-region'," + + "'baseUrl': 'http://localhost:8447'," + + "'module': '/aai/v13/'," + + "'URI': 'cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3'}"; + + public String inputGETScheduledDefault = "{" + + "'cacheKey': 'cloud-region'," + + "'baseUrl': 'http://localhost:8447'," + + "'module': '/aai/v13/'," + + "'timingIndicator': 'scheduled'," + + "'URI': 'cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3'}"; + + public String inputGETScheduledWithSyncInterval = "{" + + "'cacheKey': 'cloud-region'," + + "'baseUrl': 'http://localhost:8447'," + + "'module': '/aai/v13/'," + + "'syncInterval': '2'," + + "'timingIndicator': 'scheduled'," + + "'URI': 'cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3'}"; + + public String inputGETScheduledWithSyncIntervalWithId = "{" + + "'_id': 'cloud-region'," + + "'baseUrl': 'http://localhost:8447'," + + "'module': '/aai/v13/'," + + "'syncInterval': '2'," + + "'timingIndicator': 'scheduled'," + + "'URI': 'cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3'}"; + + + @Test + public void testCacheKeyObjectGETOnInit() { + JsonParser parser = new JsonParser(); + JsonObject ckJson = (JsonObject) parser.parse(inputGETOnInit); + CacheKey ck = CacheKey.fromJson(ckJson); + assertEquals("cacheKey was incorrect", "cloud-region", ck.getCacheKey()); + assertEquals("baseUrl was incorrect", "http://localhost:8447", ck.getBaseUrl()); + assertEquals("Module was incorrect", "/aai/v13/", ck.getModule()); + assertEquals("URI was incorrect", "cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3", ck.getURI()); + assertEquals("timingIndicator was incorrect", "onInit", ck.getTimingIndicator()); + assertEquals("Http Method was incorrect", "GET", ck.getHttpMethod()); + assertEquals("Http Body was incorrect", "-1", ck.getHttpBody()); + assertEquals("Sync Interval was incorrect", "-1", ck.getSyncInterval()); + assertEquals("Last Sync Start Time was incorrect", "-1", ck.getLastSyncStartTime()); + assertEquals("Last Sync Success Time was incorrect", "-1", ck.getLastSyncSuccessTime()); + } + + @Test + public void testCacheKeyObjectGETFirstHitDefault() { + JsonParser parser = new JsonParser(); + JsonObject ckJson = (JsonObject) parser.parse(inputGETFirstHitDefault); + CacheKey ck = CacheKey.fromJson(ckJson); + assertEquals("cacheKey was incorrect", "cloud-region", ck.getCacheKey()); + assertEquals("baseUrl was incorrect", "http://localhost:8447", ck.getBaseUrl()); + assertEquals("Module was incorrect", "/aai/v13/", ck.getModule()); + assertEquals("URI was incorrect", "cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3", ck.getURI()); + assertEquals("timingIndicator was incorrect", "firstHit", ck.getTimingIndicator()); + assertEquals("Http Method was incorrect", "GET", ck.getHttpMethod()); + assertEquals("Http Body was incorrect", "-1", ck.getHttpBody()); + assertEquals("Sync Interval was incorrect", "-1", ck.getSyncInterval()); + assertEquals("Last Sync Start Time was incorrect", "-1", ck.getLastSyncStartTime()); + assertEquals("Last Sync Success Time was incorrect", "-1", ck.getLastSyncSuccessTime()); + } + + @Test + public void testCacheKeyObjectDefaults() { + JsonParser parser = new JsonParser(); + JsonObject ckJson = (JsonObject) parser.parse("{}"); + CacheKey ck = CacheKey.fromJson(ckJson); + assertEquals("cacheKey was incorrect", "-1", ck.getCacheKey()); + assertEquals("baseUrl was incorrect", "-1", ck.getBaseUrl()); + assertEquals("Module was incorrect", "-1", ck.getModule()); + assertEquals("URI was incorrect", "-1", ck.getURI()); + assertEquals("timingIndicator was incorrect", "firstHit", ck.getTimingIndicator()); + assertEquals("Http Method was incorrect", "GET", ck.getHttpMethod()); + assertEquals("Http Body was incorrect", "-1", ck.getHttpBody()); + assertEquals("Sync Interval was incorrect", "-1", ck.getSyncInterval()); + assertEquals("Last Sync Start Time was incorrect", "-1", ck.getLastSyncStartTime()); + assertEquals("Last Sync Success Time was incorrect", "-1", ck.getLastSyncSuccessTime()); + } + + @Test + public void testCacheKeyObjectGETScheduled() { + JsonParser parser = new JsonParser(); + JsonObject ckJson = (JsonObject) parser.parse(inputGETScheduledDefault); + CacheKey ck = CacheKey.fromJson(ckJson); + assertEquals("cacheKey was incorrect", "cloud-region", ck.getCacheKey()); + assertEquals("baseUrl was incorrect", "http://localhost:8447", ck.getBaseUrl()); + assertEquals("Module was incorrect", "/aai/v13/", ck.getModule()); + assertEquals("URI was incorrect", "cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3", ck.getURI()); + assertEquals("timingIndicator was incorrect", "scheduled", ck.getTimingIndicator()); + assertEquals("Http Method was incorrect", "GET", ck.getHttpMethod()); + assertEquals("Http Body was incorrect", "-1", ck.getHttpBody()); + assertEquals("Sync Interval was incorrect", "1440", ck.getSyncInterval()); + assertEquals("Last Sync Start Time was incorrect", "-1", ck.getLastSyncStartTime()); + assertEquals("Last Sync Success Time was incorrect", "-1", ck.getLastSyncSuccessTime()); + } + + @Test + public void testCacheKeyObjectGETScheduledWithSyncInterval() { + JsonParser parser = new JsonParser(); + JsonObject ckJson = (JsonObject) parser.parse(inputGETScheduledWithSyncInterval); + CacheKey ck = CacheKey.fromJson(ckJson); + assertEquals("cacheKey was incorrect", "cloud-region", ck.getCacheKey()); + assertEquals("baseUrl was incorrect", "http://localhost:8447", ck.getBaseUrl()); + assertEquals("Module was incorrect", "/aai/v13/", ck.getModule()); + assertEquals("URI was incorrect", "cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3", ck.getURI()); + assertEquals("timingIndicator was incorrect", "scheduled", ck.getTimingIndicator()); + assertEquals("Http Method was incorrect", "GET", ck.getHttpMethod()); + assertEquals("Http Body was incorrect", "-1", ck.getHttpBody()); + assertEquals("Sync Interval was incorrect", "2", ck.getSyncInterval()); + assertEquals("Last Sync Start Time was incorrect", "-1", ck.getLastSyncStartTime()); + assertEquals("Last Sync Success Time was incorrect", "-1", ck.getLastSyncSuccessTime()); + } + + @Test + public void testCacheKeyObjectGETScheduledWithSyncIntervalWithId() { + JsonParser parser = new JsonParser(); + JsonObject ckJson = (JsonObject) parser.parse(inputGETScheduledWithSyncIntervalWithId); + CacheKey ck = CacheKey.fromJson(ckJson); + assertEquals("cacheKey was incorrect", "cloud-region", ck.getCacheKey()); + assertEquals("baseUrl was incorrect", "http://localhost:8447", ck.getBaseUrl()); + assertEquals("Module was incorrect", "/aai/v13/", ck.getModule()); + assertEquals("URI was incorrect", "cloud-infrastructure/cloud-regions?depth=0&resultIndex=1&resultSize=3", ck.getURI()); + assertEquals("timingIndicator was incorrect", "scheduled", ck.getTimingIndicator()); + assertEquals("Http Method was incorrect", "GET", ck.getHttpMethod()); + assertEquals("Http Body was incorrect", "-1", ck.getHttpBody()); + assertEquals("Sync Interval was incorrect", "2", ck.getSyncInterval()); + assertEquals("Last Sync Start Time was incorrect", "-1", ck.getLastSyncStartTime()); + assertEquals("Last Sync Success Time was incorrect", "-1", ck.getLastSyncSuccessTime()); + } +} diff --git a/src/test/java/org/onap/aai/cacher/service/helper/CacheHelperServiceScenariosTest.java b/src/test/java/org/onap/aai/cacher/service/helper/CacheHelperServiceScenariosTest.java new file mode 100644 index 0000000..f4543ad --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/service/helper/CacheHelperServiceScenariosTest.java @@ -0,0 +1,232 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.helper; + +import com.mongodb.DB; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoDatabase; +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodProcess; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongoCmdOptionsBuilder; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aai.cacher.common.MongoHelperSingleton; +import org.onap.aai.cacher.egestion.printer.EgestionTestComponent; +import org.onap.aai.cacher.injestion.parser.InjestionTestComponent; +import org.onap.aai.cacher.injestion.parser.strategy.PayloadParserType; +import org.onap.aai.cacher.model.CacheKey; +import org.onap.aai.cacher.util.AAIConstants; +import org.onap.aai.exceptions.AAIException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.ws.rs.core.Response; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@Configuration +@ContextConfiguration(classes = {InjestionTestComponent.class, EgestionTestComponent.class, CacheHelperServiceScenariosTest.class}) +public class CacheHelperServiceScenariosTest { + + private String aaiGetAllComplexResponse = + "{" + + " 'complex': [" + + " {" + + " 'physical-location-id': 'physical-location-id-1'," + + " 'resource-version': '1'" + + " }," + + " {" + + " 'physical-location-id': 'physical-location-id-2'," + + " 'resource-version': '2'" + + " }" + + " ]" + + "}"; + + private String idForDeleteCache = "/cloud-infrastructure/complexes/complex/physical-location-id-2"; + + + private static final String DB_NAME = CacheHelperServiceScenariosTest.class.getSimpleName(); + private static MongoDatabase mongoDb; + private static RestClientHelperService restClientHelperService; + private static DB db; + private static MongodProcess mongod; + private static MongoClient mongoC; + + + @Autowired + private CacheHelperService cacheHelperService; + + @Bean + public DB db() { + return db; + } + + @Bean + public MongoDatabase mongoDatabase() { + return mongoDb; + } + + @Bean + public RestClientHelperService restClientHelperService() { + return restClientHelperService; + } + + @Bean + public MongoHelperSingleton mongoHelperSingleton(DB db, MongoDatabase mongoDb) { + return new MongoHelperSingleton(db, mongoDb); + } + + @Bean + public CacheHelperService cacheHelperService() { + return new CacheHelperService(); + } + + @BeforeClass + public static void setup() throws IOException, InterruptedException { + + String bindIp = "localhost"; + int port = 27017; + startEmbedded(port); + + mongoC = new MongoClient(bindIp, port); + mongoDb = mongoC.getDatabase(DB_NAME); + db = mongoC.getDB(DB_NAME); + + } + + protected static void startEmbedded(int port) throws IOException { + IMongodConfig mongoConfigConfig = new MongodConfigBuilder() + .version(Version.Main.PRODUCTION) + .net(new Net(port, Network.localhostIsIPv6())) + .cmdOptions(new MongoCmdOptionsBuilder().verbose(true).build()) + .configServer(false) + .build(); + + MongodExecutable mongodExecutable = MongodStarter.getDefaultInstance().prepare(mongoConfigConfig); + + mongod = mongodExecutable.start(); + } + + @AfterClass + public static void tearDown() { + if (mongod != null && mongod.isProcessRunning()) { + mongod.stop(); + } + } + + @After + public void cleanup() { + final List<String> collectionNames = new ArrayList<>(); + mongoDb.listCollections().iterator().forEachRemaining(document -> collectionNames.add(document.getString("name"))); + collectionNames.forEach(collectionName -> mongoDb.getCollection(collectionName).drop()); + } + + + @Test + public void cacheKeyProcessingTest() throws Exception { + + CacheKey ck = new CacheKey("complex"); + cacheHelperService.addCacheKey(ck); + Response resp = cacheHelperService.getAllKeys(); + assertEquals("getAllKeys", 200, resp.getStatus()); + CacheKey ck1 = new CacheKey("pserver"); + ck1.timingIndicator = "scheduled"; + cacheHelperService.addCacheKey(ck1); + resp = cacheHelperService.getAllKeys(); + assertEquals("getAllKeys", 200, resp.getStatus()); + CacheKey retrieveCk = cacheHelperService.retrieveCacheKeyObject(ck); + assertEquals("retrieved cacheKey complex", "complex", retrieveCk.getCacheKey()); + + retrieveCk.setParserStrategy(PayloadParserType.AAI_RESOURCE_GET_ALL.toString()); + cacheHelperService.updateCacheKey(retrieveCk); + assertEquals("retrieved cacheKey complex", PayloadParserType.AAI_RESOURCE_GET_ALL.toString(), retrieveCk.getParserStrategy()); + assertEquals("getScheduledCaches", 1, cacheHelperService.getScheduledCaches().size()); + + resp = cacheHelperService.populateCache(retrieveCk, aaiGetAllComplexResponse); + assertEquals("populateCache", 201, resp.getStatus()); + resp = cacheHelperService.getData(retrieveCk); + assertEquals("getData", 200, resp.getStatus()); + resp = cacheHelperService.retrieveCollectionByKey(retrieveCk, AAIConstants.COLLECTION_CACHEKEY); + assertEquals("retrieveCollectionByKey", 200, resp.getStatus()); + resp = cacheHelperService.deleteCache(idForDeleteCache, "complex"); + assertEquals("deleteCache1", 204, resp.getStatus()); + resp = cacheHelperService.deleteCache("noSuchId", "complex"); + assertEquals("deleteCache2", 404, resp.getStatus()); + + + assertTrue("isShouldTrigger1", cacheHelperService.isShouldTrigger(retrieveCk)); + long current = System.currentTimeMillis(); + DateFormat formatter = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ"); + String syncStartTime = formatter.format(current - 61000); + String syncEndTime = formatter.format(current - 60500); + // setup sync in progress + retrieveCk.syncInterval = "1"; + retrieveCk.lastSyncStartTime = syncEndTime; + retrieveCk.lastSyncEndTime = syncStartTime; + cacheHelperService.updateCacheKey(retrieveCk); + + resp = cacheHelperService.forceSync(retrieveCk); + assertEquals("forceSync", 500, resp.getStatus()); + retrieveCk.lastSyncStartTime = syncStartTime; + retrieveCk.lastSyncEndTime = syncEndTime; + assertTrue("isShouldTrigger2", cacheHelperService.isShouldTrigger(retrieveCk)); + + resp = cacheHelperService.deleteCacheKeyAndAssociatedCache("complex"); + assertEquals("deleteCacheKeyAndAssociatedCache", 204, resp.getStatus()); + List<CacheKey> ckList = new ArrayList<CacheKey>(); + ck = new CacheKey("pnf"); + ck1 = new CacheKey("logical-link"); + ckList.add(ck); + ckList.add(ck1); + assertTrue(cacheHelperService.bulkAddCacheKeys(ckList)); + + } + + @Test + public void buildResponseTest() throws Exception { + List<String> issueList = Arrays.asList("First Issue", "Second Issue"); + Response resp = cacheHelperService.buildValidationResponse(issueList); + assertEquals("buildValidationResponse", 400, resp.getStatus()); + AAIException ex = new AAIException("AAI_4000"); + resp = cacheHelperService.buildExceptionResponse(ex); + assertEquals("buildExceptionResponse", 500, resp.getStatus()); + + } +} diff --git a/src/test/java/org/onap/aai/cacher/service/helper/CacheHelperServiceTest.java b/src/test/java/org/onap/aai/cacher/service/helper/CacheHelperServiceTest.java new file mode 100644 index 0000000..4a2ed94 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/service/helper/CacheHelperServiceTest.java @@ -0,0 +1,88 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.helper; + +import org.junit.Test; +import org.onap.aai.cacher.model.CacheKey; + +import java.text.SimpleDateFormat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CacheHelperServiceTest { + + private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ"); + + @Test + public void isShouldTrigger1() throws Exception { + + CacheKey cacheKey = new CacheKey("test"); + cacheKey.setLastSyncStartTime("-1"); + cacheKey.setLastSyncEndTime("-1"); + cacheKey.setLastSyncSuccessTime("-1"); + cacheKey.setSyncInterval("1"); + + CacheHelperService cacheHelperService = new CacheHelperService(); + assertTrue("No timings set (should trigger)", cacheHelperService.isShouldTrigger(cacheKey)); + } + + @Test + public void isShouldTrigger2() throws Exception { + + CacheKey cacheKey = new CacheKey("test"); + cacheKey.setLastSyncStartTime(sdf.format(System.currentTimeMillis()-300000)); //5 mins ago + cacheKey.setLastSyncEndTime("-1"); // has not ended + cacheKey.setLastSyncSuccessTime("-1"); + cacheKey.setSyncInterval("1"); //1 min interval + + CacheHelperService cacheHelperService = new CacheHelperService(); + assertFalse("Start time set (should not trigger)", cacheHelperService.isShouldTrigger(cacheKey)); + } + + @Test + public void isShouldTrigger3() throws Exception { + + CacheKey cacheKey = new CacheKey("test"); + cacheKey.setLastSyncStartTime(sdf.format(System.currentTimeMillis()-300000)); //5 mins ago + cacheKey.setLastSyncEndTime(sdf.format(System.currentTimeMillis()-240000)); // 4 mins ago + cacheKey.setLastSyncSuccessTime("-1"); + cacheKey.setSyncInterval("1"); //1 min interval + + CacheHelperService cacheHelperService = new CacheHelperService(); + assertTrue("Start time less than endtime (should trigger)", cacheHelperService.isShouldTrigger(cacheKey)); + } + + @Test + public void isShouldTrigger4() throws Exception { + + CacheKey cacheKey = new CacheKey("test"); + cacheKey.setLastSyncStartTime(sdf.format(System.currentTimeMillis()-300000)); //5 mins ago + cacheKey.setLastSyncEndTime(sdf.format(System.currentTimeMillis()-360000)); // 6 mins ago + cacheKey.setLastSyncSuccessTime("-1"); + cacheKey.setSyncInterval("1"); //1 min interval + + CacheHelperService cacheHelperService = new CacheHelperService(); + assertFalse("Start time greater than endtime (should not trigger)", cacheHelperService.isShouldTrigger(cacheKey)); + } + + + +}
\ No newline at end of file diff --git a/src/test/java/org/onap/aai/cacher/service/helper/CrudOperationsTest.java b/src/test/java/org/onap/aai/cacher/service/helper/CrudOperationsTest.java new file mode 100644 index 0000000..1aa1d81 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/service/helper/CrudOperationsTest.java @@ -0,0 +1,409 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.helper; + +import com.github.fakemongo.Fongo; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.FindOneAndUpdateOptions; +import com.mongodb.client.model.UpdateOptions; +import org.bson.Document; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class CrudOperationsTest { + + public static final String DB_NAME = "testDb"; + private static MongoDatabase mongoDatabase; + + @BeforeClass + public static void setup() { + Fongo fongo = new Fongo(DB_NAME); + mongoDatabase = fongo.getDatabase(DB_NAME); + } + + @Test + public void insertOrUpdateObjInCollection() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery1 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery1, newObj, new UpdateOptions().upsert(true)); + + Document findQuery2 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\"}"); + newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\",\"hostname\":\"testPserver_2\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery2, newObj, new UpdateOptions().upsert(true)); + + newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\",\"hostname\":\"testPserver_2\",\"equip-type\":\"NEW\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery2, newObj, new UpdateOptions().upsert(true)); + + FindIterable<Document> docs = collection.find(); + int counter = 0; + for (Document doc : docs) { + counter++; + } + assertEquals("collection contains 2 document", 2, counter); + + Document doc = collection.find(findQuery1).first(); + assertEquals("Found testPserver_1", "testPserver_1", doc.getString("hostname")); + + doc = collection.find(findQuery2).first(); + assertEquals("Found testPserver_2", "testPserver_2", doc.getString("hostname")); + assertEquals("testPserver_2 has NEW as equip-type", "NEW", doc.getString("equip-type")); + } + + @Test + public void removeObjectFromCollection() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery1 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery1, newObj, new UpdateOptions().upsert(true)); + + Document findQuery2 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\"}"); + newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\",\"hostname\":\"testPserver_2\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery2, newObj, new UpdateOptions().upsert(true)); + + assertEquals("PRE DELETE: collection contains 2 documents", 2, collection.count()); + + collection.deleteOne(findQuery1); + + assertEquals("POST DELETE: collection contains 1 documents", 1, collection.count()); + + + } + + @Test + public void findOneFromCollection() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery1 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery1, newObj, new UpdateOptions().upsert(true)); + + Document findQuery2 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\"}"); + newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\",\"hostname\":\"testPserver_2\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery2, newObj, new UpdateOptions().upsert(true)); + + Document findQuery = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_2\"}"); + + assertEquals("collection contains 1 document with id /cloud-infrastructure/pservers/pserver/testPserver_2", + 1L, collection.count(findQuery)); + } + + @Test + public void findFromCollectionWithNested() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery1 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery1, newObj, new UpdateOptions().upsert(true)); + + Document findQuery = Document.parse( + "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-1\"}" + ); + + assertEquals("collection contains 1 document with id /cloud-infrastructure/pservers/pserver/testPserver_2", + 1L, collection.count(findQuery)); + + + } + + @Test + public void findFromCollectionWithNestedFail() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery1 = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery1, newObj, new UpdateOptions().upsert(true)); + + Document findQuery = Document.parse( + "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-NONE\"}" + ); + + assertEquals("collection contains 1 document with id /cloud-infrastructure/pservers/pserver/testPserver_2", + 0L, collection.count(findQuery)); + + } + + + @Test + public void addToNestedListWithNonExistingList() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\"}"); + collection.replaceOne(findQuery, newObj, new UpdateOptions().upsert(true)); + + //Check for existing obj + String field = "p-interfaces.p-interface"; + String obj = "{\"interface-name\":\"interface-NEW\"}"; + String nestedFindString = "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-NEW\"}"; + + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("PRE UPDATE: collection contains 0 document with id and nested field", + Long.valueOf(0L), + Long.valueOf(collection.count(nestedFind))); + + Document doc = new Document(); + doc.put(field, Document.parse(obj)); + Document push = new Document(); + push.put("$push", doc); + + System.out.println(collection.find(findQuery).first().toJson()); + + collection.findOneAndUpdate(findQuery, push, new FindOneAndUpdateOptions().upsert(true)); + + System.out.println(collection.find(findQuery).first().toJson()); + + assertEquals("POST UPDATE: collection contains 1 document with id and nested field", + Long.valueOf(1L), + Long.valueOf(collection.count(nestedFind))); + + } + + @Test + public void addToNestedExistingList() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery, newObj, new UpdateOptions().upsert(true)); + + //Check for existing obj + String field = "p-interfaces.p-interface"; + String obj = "{\"interface-name\":\"interface-NEW\"}"; + String nestedFindString = "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-NEW\"}"; + + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("PRE UPDATE: collection contains 0 document with id and nested field", + Long.valueOf(0L), + Long.valueOf(collection.count(nestedFind))); + + Document doc = new Document(); + doc.put(field, Document.parse(obj)); + Document push = new Document(); + push.put("$push", doc); + + System.out.println(collection.find(findQuery).first().toJson()); + + collection.findOneAndUpdate(findQuery, push, new FindOneAndUpdateOptions().upsert(true)); + + System.out.println(collection.find(findQuery).first().toJson()); + + assertEquals("POST UPDATE: collection contains 1 document with id and nested field", + Long.valueOf(1L), + Long.valueOf(collection.count(nestedFind))); + + } + + @Test + public void addToNestedWhereNestedObjExists() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document findQuery = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"}"); + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\",\"equip-type\":\"JUNIPER XXXX\",\"p-interfaces\":{\"p-interface\":[{\"interface-name\":\"interface-1\"}]}}"); + collection.replaceOne(findQuery, newObj, new UpdateOptions().upsert(true)); + + //Check for existing obj + String field = "p-interfaces.p-interface"; + String obj = "{\"interface-name\":\"interface-NEW\",\"new-field\":\"NEW\"}"; + String nestedFindString = "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-1\"}"; + String nestedFindUsingNewFieldString = "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.new-field\":\"NEW\"}"; + String nestedFieldPull = "{\"p-interfaces.p-interface\":{\"interface-name\":\"interface-1\"}}"; + + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("PRE UPDATE: collection contains 1 document with id and nested field", + Long.valueOf(1L), + Long.valueOf(collection.count(nestedFind))); + assertEquals("PRE UPDATE: collection contains 0 document with id and new nested field", + Long.valueOf(0L), + Long.valueOf(collection.count(Document.parse(nestedFindUsingNewFieldString)))); + + //REMOVE existing + Document pull = new Document(); + pull.put("$pull", Document.parse(nestedFieldPull)); + + collection.findOneAndUpdate(nestedFind, pull); + + assertEquals("PRE UPDATE POST DELETE: collection no longer the nested obj that will be inserted", + Long.valueOf(0L), + Long.valueOf(collection.count(nestedFind))); + + + Document doc = new Document(); + doc.put(field, Document.parse(obj)); + Document push = new Document(); + push.put("$push", doc); + + System.out.println(collection.find(findQuery).first().toJson()); + + collection.findOneAndUpdate(findQuery, push, new FindOneAndUpdateOptions().upsert(true)); + + System.out.println(collection.find(findQuery).first().toJson()); + + assertEquals("POST UPDATE: collection contains 1 document with id and nested field", + Long.valueOf(1L), + Long.valueOf(collection.count(Document.parse(nestedFindUsingNewFieldString)))); + + } + + @Test + public void addToNestedWhereNestedObjExistsTwoLevels() { + String collectionName = new Object() {} + .getClass() + .getEnclosingMethod() + .getName(); + + mongoDatabase.createCollection(collectionName); + + MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName); + + Document newObj = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\",\"hostname\":\"testPserver_1\"," + + "\"p-interfaces\":{\"p-interface\":[" + + "{\"interface-name\":\"interface-1\",\"l-interfaces\":{\"l-interface\":[{\"interface-name\":\"l-interface-1\"}]}}," + + "{\"interface-name\":\"interface-2\"}" + + "]}}"); + + Document findQuery = Document.parse("{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-1\"}"); + + collection.replaceOne(findQuery, newObj, new UpdateOptions().upsert(true)); + + //Check for existing obj + String field = "p-interfaces.p-interface.$.l-interfaces.l-interface"; + String obj = "{\"interface-name\":\"l-interface-1\",\"new-field\":\"NEW\"}"; + + String nestedFindString = "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-1\"," + + "\"p-interfaces.p-interface.l-interfaces.l-interface.interface-name\":\"l-interface-1\"}"; + + String nestedFindUsingNewFieldString = "{\"_id\":\"/cloud-infrastructure/pservers/pserver/testPserver_1\"," + + "\"p-interfaces.p-interface.interface-name\":\"interface-1\"" + + "\"p-interfaces.p-interface.l-interfaces.l-interface.new-field\":\"NEW\"}"; + + String nestedFieldPull = "{\"p-interfaces.p-interface.$.l-interfaces.l-interface\":{\"interface-name\":\"l-interface-1\"}}"; + + Document nestedFind = Document.parse(nestedFindString); + + assertEquals("PRE UPDATE: collection contains 1 document with id and nested field", + Long.valueOf(1L), + Long.valueOf(collection.count(nestedFind))); + assertEquals("PRE UPDATE: collection contains 0 document with id and new nested field", + Long.valueOf(0L), + Long.valueOf(collection.count(Document.parse(nestedFindUsingNewFieldString)))); + + //REMOVE existing + Document pull = new Document(); + pull.put("$pull", Document.parse(nestedFieldPull)); + + collection.findOneAndUpdate(nestedFind, pull); + + assertEquals("PRE UPDATE POST DELETE: collection no longer the nested obj that will be inserted", + Long.valueOf(0L), + Long.valueOf(collection.count(nestedFind))); + + + Document doc = new Document(); + doc.put(field, Document.parse(obj)); + Document push = new Document(); + push.put("$push", doc); + + System.out.println(collection.find(findQuery).first().toJson()); + + collection.findOneAndUpdate(findQuery, push, new FindOneAndUpdateOptions().upsert(true)); + + System.out.println(collection.find(findQuery).first().toJson()); + + assertEquals("POST UPDATE: collection contains 1 document with id and nested field", + Long.valueOf(1L), + Long.valueOf(collection.count(Document.parse(nestedFindUsingNewFieldString)))); + + } + +}
\ No newline at end of file diff --git a/src/test/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidationTest.java b/src/test/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidationTest.java new file mode 100644 index 0000000..53f90a3 --- /dev/null +++ b/src/test/java/org/onap/aai/cacher/service/rest/util/CacheKeyRequestValidationTest.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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.aai.cacher.service.rest.util; + +import com.google.gson.JsonParser; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.aai.cacher.service.helper.CacheHelperService; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class CacheKeyRequestValidationTest { + + protected CacheHelperService cacheHelperService; + protected CacheKeyRequestValidation addCacheKeyRequestValidation; + protected CacheKeyRequestValidation updateCacheKeyRequestValidation; + + private String emptyPayload = "{}"; + private String nonEmptyPayload = "{\"cacheKey\" : \"complex\"}"; + private JsonParser parser; + + @Before + public void setup() { + cacheHelperService = Mockito.mock(CacheHelperService.class); + addCacheKeyRequestValidation = new CacheKeyRequestValidation(CacheKeyRequestValidationType.ADD); + updateCacheKeyRequestValidation = new CacheKeyRequestValidation(CacheKeyRequestValidationType.UPDATE); + parser = new JsonParser(); + } + + @Test + public void testNullPayload() { + List<String> results = addCacheKeyRequestValidation.validateCacheKeyRequest(null, cacheHelperService); + assertEquals("null payload ok", "Unsupported CacheKey request format, empty payload.", results.get(0)); + } + + @Test + public void testEmptyPayload() { + List<String> results = addCacheKeyRequestValidation.validateCacheKeyRequest(parser.parse(emptyPayload).getAsJsonObject(), cacheHelperService); + assertEquals("empty payload ok", "Unsupported CacheKey request format, unspecified cacheKey.", results.get(0)); + } + + @Test + public void testAddNewCacheKey() { + Mockito.when(cacheHelperService.isKeyPresent(Mockito.any(), Mockito.anyString())).thenReturn(false); + List<String> results = addCacheKeyRequestValidation.validateCacheKeyRequest(parser.parse(nonEmptyPayload).getAsJsonObject(), cacheHelperService); + assertEquals("add new CacheKey ok", 0, results.size()); + } + + @Test + public void testAddExistingCacheKey() { + Mockito.when(cacheHelperService.isKeyPresent(Mockito.any(), Mockito.anyString())).thenReturn(true); + List<String> results = addCacheKeyRequestValidation.validateCacheKeyRequest(parser.parse(nonEmptyPayload).getAsJsonObject(), cacheHelperService); + assertEquals("add existing CacheKey ok", "Invalid request to add cacheKey complex, cacheKey exists.", results.get(0)); + } + + + @Test + public void testUpdateNewCacheKey() { + Mockito.when(cacheHelperService.isKeyPresent(Mockito.any(), Mockito.anyString())).thenReturn(false); + List<String> results = updateCacheKeyRequestValidation.validateCacheKeyRequest(parser.parse(nonEmptyPayload).getAsJsonObject(), cacheHelperService); + assertEquals("update new CacheKey ok", "Invalid request to update cacheKey complex, cacheKey does not exist.", results.get(0)); + } + + @Test + public void testUpdateExistingCacheKey() { + Mockito.when(cacheHelperService.isKeyPresent(Mockito.any(), Mockito.anyString())).thenReturn(true); + List<String> results = updateCacheKeyRequestValidation.validateCacheKeyRequest(parser.parse(nonEmptyPayload).getAsJsonObject(), cacheHelperService); + assertEquals("update existing CacheKey ok", 0, results.size()); + } +} diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties new file mode 100644 index 0000000..5439e9f --- /dev/null +++ b/src/test/resources/application-test.properties @@ -0,0 +1,14 @@ +info.build.artifact=@project.artifactId@ +info.build.name=@project.name@ +info.build.description=@project.description@ +info.build.version=@project.version@ + +spring.jersey.type=filter + +logging.level.root=info +logging.level.org.glassfish=info +logging.level.org.glassfish.jersey=info + +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration + +logging.pattern.console=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr($ threadId: {PID:- }){magenta} %clr(---){faint} %clr([ hostname: %X{hostname} serviceName: %X{serviceName} version: %X{version} transactionId: %X{transactionId} requestTimeStamp: %X{requestTimestamp} responseTimeStamp: %X{responseTimestamp} duration: %X{duration}]){yellow} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaap-pserver-create.json b/src/test/resources/test/payloads/dmaap-pserver-create.json new file mode 100644 index 0000000..735817d --- /dev/null +++ b/src/test/resources/test/payloads/dmaap-pserver-create.json @@ -0,0 +1,100 @@ +{ + "cambria.partition": "AAI", + "event-header": + { + "severity": "NORMAL", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v12/cloud-infrastructure/pservers/pserver/dmaap-pserver-create", + "event-type": "AAI-EVENT", + "domain": "test", + "action": "CREATE", + "sequence-number": "0", + "id": "id-dmaap-pserver-create", + "source-name": "test", + "version": "v12", + "timestamp": "20180508-17:50:11:681" + }, + "entity": + { + "hostname": "dmaap-pserver-create", + "equip-type": "JUNIPER XXXX", + "relationship-list": + { + "relationship": [ + { + "related-to": "complex", + "relationship-data": [ + { + "relationship-value": "CHARILWJNA0", + "relationship-key": "complex.physical-location-id" + } + ], + "related-link": "/aai/v12/cloud-infrastructure/complexes/complex/CHARILWJNA0", + "relationship-label": "org.onap.relationships.inventory.LocatedIn" + } + ] + }, + "equip-vendor": "JUNIPER", + "equip-model": "NFX250-XYZ-LS1", + "in-maint": false, + "serial-number": "", + "resource-version": "1525801811662", + "pserver-id": "0A47B945-9C74-4CBE-AD72-0DECB966EB94", + "p-interfaces": + { + "p-interface": [ + { + "interface-name": "ge-0/0/10", + "relationship-list": + { + "relationship": [ + { + "related-to": "physical-link", + "relationship-label": "tosca.relationships.network.LinksTo", + "related-link": "/aai/v12/network/physical-links/physical-link/HIS.1702.03053.121", + "relationship-data": [ + { + "relationship-key": "physical-link.link-name", + "relationship-value": "HIS.1702.03053.121" + } + ] + } + ] + } + }, + { + "interface-name": "ge-0/0/11", + "relationship-list": + { + "relationship": [ + { + "related-to": "vserver", + "relationship-label": "tosca.relationships.HostedOn", + "related-link": "/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/SERVERNAME%3A%3AXXXX/vservers/vserver/afce2113-297a-436c-811a-acf9981fff68", + "relationship-data": [ + { + "relationship-key": "cloud-region.cloud-owner", + "relationship-value": "onap-cloud-owner" + }, + { + "relationship-key": "cloud-region.cloud-region-id", + "relationship-value": "AAIAIC25" + }, + { + "relationship-key": "tenant.tenant-id", + "relationship-value": "SERVERNAME::XXXX" + }, + { + "relationship-key": "vserver.vserver-id", + "relationship-value": "afce2113-297a-436c-811a-acf9981fff68" + } + ] + } + ] + } + } + ] + } + } +} diff --git a/src/test/resources/test/payloads/dmaapEvents/address-list.json b/src/test/resources/test/payloads/dmaapEvents/address-list.json new file mode 100644 index 0000000..b2ea6b8 --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/address-list.json @@ -0,0 +1,47 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "l3-interface-ipv4-address-list", + "top-entity-type": "generic-vnf", + "entity-link": "/aai/v13/network/generic-vnfs/generic-vnf/generic-vnf-987654321-39-jenkins/l-interfaces/l-interface/interface-name-generic-vnf-987654321-39-jenkins/vlans/vlan/vlan-interface-generic-vnf-987654321-39-jenkins/l3-interface-ipv4-address-list/l3-interface-ipv4-address-generic-vnf-987654321-39-jenkins", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "DELETE", + "sequence-number": "0", + "id": "7a899562-a0c1-414e-83aa-0021a5c7646b", + "source-name": "FitNesse-Test-generic-vnf-AAI-9278-02", + "version": "v13", + "timestamp": "20180625-00:05:26:664" + }, + "entity": { + "vnf-id": "generic-vnf-987654321-39-jenkins", + "l-interfaces": { + "l-interface": [ + { + "vlans": { + "vlan": [ + { + "vlan-interface": "vlan-interface-generic-vnf-987654321-39-jenkins", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 79781362, + "resource-version": "1529885125714", + "neutron-network-id": "example-neutron-network-id-val-73336", + "neutron-subnet-id": "example-neutron-subnet-id-val-86272", + "vlan-id-inner": 8858186, + "l3-interface-ipv4-address": "l3-interface-ipv4-address-generic-vnf-987654321-39-jenkins", + "is-floating": true, + "vlan-id-outer": 5350919 + } + ] + } + ] + }, + "interface-name": "interface-name-generic-vnf-987654321-39-jenkins" + } + ] + }, + "vnf-name": "example-vnf-name-val-21021" + } +}
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/1-create-logical-link.json b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/1-create-logical-link.json new file mode 100644 index 0000000..5277b3d --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/1-create-logical-link.json @@ -0,0 +1,20 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "logical-link", + "top-entity-type": "logical-link", + "entity-link": "/aai/v13/network/logical-links/logical-link/logical-link", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "CREATE", + "sequence-number": "0", + "id": "fe89fd6b-8b1b-4ab6-8b3a-d5bb7942dbee", + "source-name": "junit", + "version": "v13", + "timestamp": "20180712-17:47:24:042" + }, + "entity": { + "link-name": "logical-link" + } +}
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/2-create-generic-vnf.json b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/2-create-generic-vnf.json new file mode 100644 index 0000000..57fe6a2 --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/2-create-generic-vnf.json @@ -0,0 +1,32 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "generic-vnf", + "top-entity-type": "generic-vnf", + "entity-link": "/aai/v13/network/generic-vnfs/generic-vnf/generic-vnf-id", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "CREATE", + "sequence-number": "0", + "id": "d56359e7-4dcb-471a-9a6a-2afbb353b5bd", + "source-name": "junit", + "version": "v13", + "timestamp": "20180712-17:47:24:440" + }, + "entity": { + "vnf-id": "generic-vnf-id", + "l-interfaces": { + "l-interface": [{ + "vlans": { + "vlan": [{ + "vlan-interface": "vlan-1" + } + ] + }, + "interface-name": "l-interface-name-1" + } + ] + } + } +}
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/3-create-rel-generic-vnf-vlan-to-logical-link.json b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/3-create-rel-generic-vnf-vlan-to-logical-link.json new file mode 100644 index 0000000..bdfabe8 --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/3-create-rel-generic-vnf-vlan-to-logical-link.json @@ -0,0 +1,45 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "vlan", + "top-entity-type": "generic-vnf", + "entity-link": "/aai/v13/network/generic-vnfs/generic-vnf/generic-vnf-id/l-interfaces/l-interface/l-interface-name-1/vlans/vlan/vlan-1", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "UPDATE", + "sequence-number": "0", + "id": "bd2bc927-d28b-4472-a582-317c4c19c98b", + "source-name": "FitNesse-Relationship-Test-ps2418", + "version": "v13", + "timestamp": "20180712-17:47:24:609" + }, + "entity": { + "vnf-id": "generic-vnf-id", + "l-interfaces": { + "l-interface": [{ + "vlans": { + "vlan": [{ + "relationship-list": { + "relationship": [{ + "related-to": "logical-link", + "relationship-data": [{ + "relationship-value": "logical-link", + "relationship-key": "logical-link.link-name" + } + ], + "related-link": "/aai/v13/network/logical-links/logical-link/logical-link", + "relationship-label": "org.onap.relationships.inventory.Uses" + } + ] + }, + "vlan-interface": "vlan-1" + } + ] + }, + "interface-name": "l-interface-name-1" + } + ] + } + } +}
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/4-delete-rel-to-generic-vnf-vlan-from-logical-link.json b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/4-delete-rel-to-generic-vnf-vlan-from-logical-link.json new file mode 100644 index 0000000..20c2278 --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/deleteRelationship/4-delete-rel-to-generic-vnf-vlan-from-logical-link.json @@ -0,0 +1,20 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "logical-link", + "top-entity-type": "logical-link", + "entity-link": "/aai/v13/network/logical-links/logical-link/logical-link", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "UPDATE", + "sequence-number": "0", + "id": "3f9ea0cf-da42-4a9e-817b-7fb1eab0cabe", + "source-name": "junit", + "version": "v13", + "timestamp": "20180712-17:47:25:057" + }, + "entity": { + "link-name": "logical-link" + } +}
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaapEvents/large-pserver.json b/src/test/resources/test/payloads/dmaapEvents/large-pserver.json new file mode 100644 index 0000000..1d7cf14 --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/large-pserver.json @@ -0,0 +1,2088 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v13/cloud-infrastructure/pservers/pserver/c9e8ffb6-a360-4f9c-96c3-f5f0244dfe55-jenkins", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "UPDATE", + "sequence-number": "0", + "id": "5cc57cd2-c55c-4bbc-bf92-cba20b6d2bf3", + "source-name": "FitNesse-Test-jenkins", + "version": "v13", + "timestamp": "20180625-01:24:01:437" + }, + "entity": { + "ptnii-equip-name": "ly3mdbqA7Gaha", + "ipaddress-v6-loopback-0": "VWN", + "equip-vendor": "zfK", + "purpose": "pxyHYQ6", + "pserver-selflink": "xS4YnSMvWpX", + "number-of-cpus": 359, + "ipaddress-v6-aim": "7vxG9SYzaH", + "pserver-name2": "iqFmGNmNLM6", + "hostname": "c9e8ffb6-a360-4f9c-96c3-f5f0244dfe55-jenkins", + "inv-status": "pS24ORbjyauE", + "disk-in-gigabytes": 509, + "equip-type": "41kdNkU", + "fqdn": "ldTOgy", + "serial-number": "5iYx0byET", + "ipaddress-v6-oam": "pc910", + "pserver-id": "RswqQD", + "prov-status": "pMB6hQ2XA35gL", + "ipv4-oam-address": "dQn9sGTx8T", + "ipaddress-v4-loopback-0": "qKCu9dNYq", + "lag-interfaces": { + "lag-interface": [ + { + "interface-role": "TA0roiR2Dlstf", + "speed-value": "bs6yh1DIrc", + "in-maint": true, + "resource-version": "1529889840378", + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "pRl0e9CWJ", + "vlans": { + "vlan": [ + { + "vlan-description": "RRiCxGpYLE7IG", + "vpn-key": "dENkRyQ6", + "prov-status": "YipbUEnORoUR", + "vlan-id-inner": 708, + "vlan-id-outer": 715, + "orchestration-status": "f28", + "speed-value": "nQ7rxAY1", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840437", + "neutron-network-id": "2OkhCFUDCWz", + "neutron-subnet-id": "rAkO7", + "l3-interface-ipv6-prefix-length": 880, + "vlan-id-inner": 441, + "is-floating": true, + "l3-interface-ipv6-address": "c72250d4-3718-458f-8a78-18b60ba84981-jenkins", + "vlan-id-outer": 334 + }, + { + "resource-version": "1529889840443", + "neutron-network-id": "Fjk5w3x", + "neutron-subnet-id": "CoGV7pgh0L0w", + "l3-interface-ipv6-prefix-length": 930, + "vlan-id-inner": 343, + "is-floating": true, + "l3-interface-ipv6-address": "2e33be8a-ebe9-46b9-9ed8-b68fd7fafa37-jenkins", + "vlan-id-outer": 276 + } + ], + "resource-version": "1529889840421", + "is-ip-unnumbered": false, + "speed-units": "9gi0", + "vlan-interface": "624adb22-bcf6-4efe-bc20-a1fa2fcdc8b5-jenkins", + "backdoor-connection": "VtvN8kWyDNAY", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 723, + "resource-version": "1529889840432", + "neutron-network-id": "0iGBId", + "neutron-subnet-id": "7Wv9mkgSgQMep", + "vlan-id-inner": 903, + "l3-interface-ipv4-address": "a69c17e3-9902-4ad8-9bf0-547a12144944-jenkins", + "is-floating": true, + "vlan-id-outer": 40 + }, + { + "l3-interface-ipv4-prefix-length": 816, + "resource-version": "1529889840425", + "neutron-network-id": "OHzi6OHC", + "neutron-subnet-id": "z6cy", + "vlan-id-inner": 156, + "l3-interface-ipv4-address": "efb60dd0-2f6d-40b9-9aec-f123c900088f-jenkins", + "is-floating": true, + "vlan-id-outer": 678 + } + ] + }, + { + "vlan-description": "dko1ww", + "vpn-key": "tTnYmdtMuvj", + "prov-status": "LXwvfjKwggY", + "vlan-id-inner": 785, + "vlan-id-outer": 64, + "orchestration-status": "YDueDsc", + "speed-value": "rnq", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840413", + "neutron-network-id": "9GwSXJO", + "neutron-subnet-id": "MLw92oJx", + "l3-interface-ipv6-prefix-length": 416, + "vlan-id-inner": 619, + "is-floating": true, + "l3-interface-ipv6-address": "290c0ffd-8b30-4447-b3d0-15fd7aaf3a0a-jenkins", + "vlan-id-outer": 266 + }, + { + "resource-version": "1529889840407", + "neutron-network-id": "7mhjNSDw", + "neutron-subnet-id": "CfIbyRJVK", + "l3-interface-ipv6-prefix-length": 980, + "vlan-id-inner": 15, + "is-floating": false, + "l3-interface-ipv6-address": "fe62bfe1-bb1f-430c-a73a-17129a774006-jenkins", + "vlan-id-outer": 538 + } + ], + "resource-version": "1529889840390", + "is-ip-unnumbered": true, + "speed-units": "NZnxJ0", + "vlan-interface": "ba6322cc-8a92-4c52-9f1c-e1ed151685f4-jenkins", + "backdoor-connection": "hknHtwrQ8", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 123, + "resource-version": "1529889840395", + "neutron-network-id": "S1lm", + "neutron-subnet-id": "ArbSTda9", + "vlan-id-inner": 433, + "l3-interface-ipv4-address": "39f4c806-0a69-44ce-801e-6e788dde996c-jenkins", + "is-floating": false, + "vlan-id-outer": 454 + }, + { + "l3-interface-ipv4-prefix-length": 874, + "resource-version": "1529889840402", + "neutron-network-id": "4eQNt", + "neutron-subnet-id": "jcbWZEE1iuIxo", + "vlan-id-inner": 179, + "l3-interface-ipv4-address": "bc0f320b-307f-40f0-a985-83adab31ceae-jenkins", + "is-floating": false, + "vlan-id-outer": 274 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "RtXRWVNEJADY", + "interface-name": "dc917efb-f045-4250-b3e3-1f13de0c50c6-jenkins", + "allowed-address-pairs": "xXhZud", + "prov-status": "ESgNJKvFRBbJ", + "macaddr": "J3BfKm", + "interface-role": "tRCKYmQWZr", + "selflink": "zqJy", + "in-maint": false, + "admin-status": "BbiEg3U", + "is-port-mirrored": false, + "resource-version": "1529889840457", + "is-ip-unnumbered": true, + "network-name": "p03hQIJEj", + "management-option": "qI4hY9rO", + "interface-id": "M1mVymxqCG9B", + "interface-description": "X0ylXoZxd8" + }, + { + "v6-wan-link-ip": "PuNFKRUUpd3", + "interface-name": "89796dd1-89a5-4ddc-bd13-324ba9bce3b6-jenkins", + "allowed-address-pairs": "RGo6MaADK", + "prov-status": "uot", + "macaddr": "xUj8TGre", + "interface-role": "SyT0hd9Uu4b", + "selflink": "HxDI", + "in-maint": false, + "admin-status": "GDgD", + "is-port-mirrored": true, + "resource-version": "1529889840462", + "is-ip-unnumbered": false, + "network-name": "RXCo3p3p5BhBS", + "management-option": "jNiTd", + "interface-id": "4n8niH", + "interface-description": "drnTF3" + } + ] + }, + "interface-name": "f4f9b9c7-eb83-4622-9d6f-14027a556ff5-jenkins", + "allowed-address-pairs": "tsZfdO6K", + "prov-status": "3arI73HikM", + "macaddr": "0q6FMAB", + "interface-role": "4cyrEGb5ldY", + "selflink": "baX", + "in-maint": true, + "admin-status": "NbXMnykI", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840487", + "neutron-network-id": "IHaNS4GYk8We", + "neutron-subnet-id": "Avamy", + "l3-interface-ipv6-prefix-length": 980, + "vlan-id-inner": 995, + "is-floating": true, + "l3-interface-ipv6-address": "91e884de-b2b7-471a-a245-44aeb7c134a6-jenkins", + "vlan-id-outer": 9 + }, + { + "resource-version": "1529889840481", + "neutron-network-id": "Nus6ae0m", + "neutron-subnet-id": "fA3l0lvnHdtb", + "l3-interface-ipv6-prefix-length": 809, + "vlan-id-inner": 340, + "is-floating": true, + "l3-interface-ipv6-address": "ce4f5d92-0522-4c36-9d42-57e9138a177e-jenkins", + "vlan-id-outer": 753 + } + ], + "is-port-mirrored": true, + "resource-version": "1529889840382", + "is-ip-unnumbered": false, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "0BKVj51qatJhI", + "vf-vlan-strip": false, + "neutron-network-id": "s8H", + "vf-broadcast-allow": false, + "vf-mac-anti-spoof-check": true, + "vf-unknown-multicast-allow": true, + "pci-id": "7e5a9324-386f-4328-aa77-a4f6cf7f0dbe-jenkins", + "vf-mirrors": "agzCT75g3Vg", + "resource-version": "1529889840451", + "vf-link-status": "bwtQlepGf", + "vf-mac-filter": "EkaVjcgrNl", + "vf-insert-stag": false, + "vf-vlan-anti-spoof-check": true, + "vf-unknown-unicast-allow": true + } + ] + }, + "network-name": "8BqQdZOAl2lo", + "management-option": "CY2Ta8s", + "interface-id": "6Ch", + "interface-description": "VlMDLY2l7z", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 251, + "resource-version": "1529889840474", + "neutron-network-id": "K52", + "neutron-subnet-id": "7CZjzB", + "vlan-id-inner": 790, + "l3-interface-ipv4-address": "a82b6014-8aa2-4bd8-b6e7-01c5f7a19c33-jenkins", + "is-floating": true, + "vlan-id-outer": 58 + }, + { + "l3-interface-ipv4-prefix-length": 404, + "resource-version": "1529889840468", + "neutron-network-id": "LqT0cwY4tdE", + "neutron-subnet-id": "Imj2rt0HAMGG", + "vlan-id-inner": 525, + "l3-interface-ipv4-address": "e7c633df-9024-493e-8b7f-5b10415cb1aa-jenkins", + "is-floating": true, + "vlan-id-outer": 108 + } + ] + }, + { + "v6-wan-link-ip": "Ln26J5hGX7M", + "vlans": { + "vlan": [ + { + "vlan-description": "I9JkId", + "vpn-key": "LRdP", + "prov-status": "APYZv", + "vlan-id-inner": 35, + "vlan-id-outer": 831, + "orchestration-status": "T1wt2oC", + "speed-value": "GHxANnX", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840558", + "neutron-network-id": "emLOUy0Qmmo", + "neutron-subnet-id": "fzgS9OJ", + "l3-interface-ipv6-prefix-length": 752, + "vlan-id-inner": 998, + "is-floating": false, + "l3-interface-ipv6-address": "1bfe762c-4c38-431b-b15f-ca66c8a31a28-jenkins", + "vlan-id-outer": 293 + }, + { + "resource-version": "1529889840564", + "neutron-network-id": "20qzZFzb", + "neutron-subnet-id": "RWfDmt", + "l3-interface-ipv6-prefix-length": 400, + "vlan-id-inner": 427, + "is-floating": true, + "l3-interface-ipv6-address": "4ea1cc4f-1400-494e-99c7-820b213a4c03-jenkins", + "vlan-id-outer": 270 + } + ], + "resource-version": "1529889840541", + "is-ip-unnumbered": false, + "speed-units": "9CDfulUnymX1x", + "vlan-interface": "0016f9ca-1ef3-4b14-bed0-fd9d7a5f7020-jenkins", + "backdoor-connection": "hIq", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 12, + "resource-version": "1529889840546", + "neutron-network-id": "sYe5FRwMDe", + "neutron-subnet-id": "snexxGpM", + "vlan-id-inner": 834, + "l3-interface-ipv4-address": "eae2bc5c-e72e-41b6-93f7-73a3db342e2f-jenkins", + "is-floating": true, + "vlan-id-outer": 934 + }, + { + "l3-interface-ipv4-prefix-length": 687, + "resource-version": "1529889840552", + "neutron-network-id": "OyNhYSJ", + "neutron-subnet-id": "iAE", + "vlan-id-inner": 820, + "l3-interface-ipv4-address": "c16e3d11-45cf-4ae2-aa7e-e40e23d4a454-jenkins", + "is-floating": true, + "vlan-id-outer": 12 + } + ] + }, + { + "vlan-description": "HFZ0s1sqrx", + "vpn-key": "DA3vkcsmXoNa", + "prov-status": "PLXCq2sZr", + "vlan-id-inner": 349, + "vlan-id-outer": 230, + "orchestration-status": "tIlhc9", + "speed-value": "9rk46hsxtjUJY", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840534", + "neutron-network-id": "uzY", + "neutron-subnet-id": "hevG", + "l3-interface-ipv6-prefix-length": 188, + "vlan-id-inner": 247, + "is-floating": true, + "l3-interface-ipv6-address": "418916cc-8123-4b24-8879-9f512e771c70-jenkins", + "vlan-id-outer": 995 + }, + { + "resource-version": "1529889840528", + "neutron-network-id": "9sqJYket", + "neutron-subnet-id": "TA0Ir2iH", + "l3-interface-ipv6-prefix-length": 313, + "vlan-id-inner": 619, + "is-floating": false, + "l3-interface-ipv6-address": "1812bc12-be5c-4cca-9b87-03bd19277b04-jenkins", + "vlan-id-outer": 627 + } + ], + "resource-version": "1529889840511", + "is-ip-unnumbered": true, + "speed-units": "siXy4hm", + "vlan-interface": "010547b9-4495-4fb5-a1b2-d4dbb8833e83-jenkins", + "backdoor-connection": "1F0cNOsS", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 780, + "resource-version": "1529889840522", + "neutron-network-id": "jwWHQK7", + "neutron-subnet-id": "UsxImV5pL9LL", + "vlan-id-inner": 637, + "l3-interface-ipv4-address": "d814d5bd-a23c-4f21-9f3d-2c631f424aac-jenkins", + "is-floating": false, + "vlan-id-outer": 418 + }, + { + "l3-interface-ipv4-prefix-length": 262, + "resource-version": "1529889840516", + "neutron-network-id": "JDuBaq3Cbhd", + "neutron-subnet-id": "1DFTpWjFLzcZ6", + "vlan-id-inner": 191, + "l3-interface-ipv4-address": "a1dc02f5-11eb-46cd-81e8-6e51e82f7eff-jenkins", + "is-floating": false, + "vlan-id-outer": 426 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "3J1Z18yxgQ004", + "interface-name": "9471edc4-3e56-43c1-987b-a7d50b831ffa-jenkins", + "allowed-address-pairs": "QXWns3Qp", + "prov-status": "FacORXn", + "macaddr": "hp9PJwVAD", + "interface-role": "17o1WXMEldX8", + "selflink": "brAO", + "in-maint": true, + "admin-status": "04KWsIfV3", + "is-port-mirrored": false, + "resource-version": "1529889840583", + "is-ip-unnumbered": false, + "network-name": "8xX9B4eSfixos", + "management-option": "m2w0o5B", + "interface-id": "zzbAbZvn6sT", + "interface-description": "qkWDaz1Qix" + }, + { + "v6-wan-link-ip": "PxVRinMq5Vgq4", + "interface-name": "a11a5207-4fb1-4dc2-a167-95c2712fdc35-jenkins", + "allowed-address-pairs": "oG7yZKSv6KONP", + "prov-status": "tCy3ilKzFIR", + "macaddr": "ttHiTiLtkN25z", + "interface-role": "OpQ3C", + "selflink": "dZe4nCK", + "in-maint": false, + "admin-status": "PqB6G3n16lEG", + "is-port-mirrored": false, + "resource-version": "1529889840578", + "is-ip-unnumbered": true, + "network-name": "6PQItO", + "management-option": "PK28FqG", + "interface-id": "Gpy8kn1QXK", + "interface-description": "HLG0XZ" + } + ] + }, + "interface-name": "02dc1675-e1c3-4cfb-a2e6-8aa67b6f1c2d-jenkins", + "allowed-address-pairs": "7xJnB", + "prov-status": "cMv3MM0GPOk", + "macaddr": "JVQ8SS6", + "interface-role": "r1hnvD02Xgs", + "selflink": "r3F", + "in-maint": true, + "admin-status": "4iU", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840608", + "neutron-network-id": "oLuz7jf", + "neutron-subnet-id": "ouBsOQ", + "l3-interface-ipv6-prefix-length": 421, + "vlan-id-inner": 864, + "is-floating": false, + "l3-interface-ipv6-address": "95782900-e9e2-459f-8039-e8c165a22688-jenkins", + "vlan-id-outer": 760 + }, + { + "resource-version": "1529889840602", + "neutron-network-id": "yT9BgKa5Q", + "neutron-subnet-id": "4wuHUPFV", + "l3-interface-ipv6-prefix-length": 454, + "vlan-id-inner": 775, + "is-floating": true, + "l3-interface-ipv6-address": "af360d6d-06c6-44af-ab10-7f3e253d6f5c-jenkins", + "vlan-id-outer": 733 + } + ], + "is-port-mirrored": true, + "resource-version": "1529889840504", + "is-ip-unnumbered": true, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "szyj3DJNs", + "vf-vlan-strip": true, + "neutron-network-id": "oe0yQEK2pt", + "vf-broadcast-allow": false, + "vf-mac-anti-spoof-check": false, + "vf-unknown-multicast-allow": false, + "pci-id": "1e9a98ce-5235-47d3-ab4b-d106c77eac4f-jenkins", + "vf-mirrors": "RLPA", + "resource-version": "1529889840572", + "vf-link-status": "7cbMLgWUQCA", + "vf-mac-filter": "6MFqin1N10K", + "vf-insert-stag": true, + "vf-vlan-anti-spoof-check": true, + "vf-unknown-unicast-allow": false + } + ] + }, + "network-name": "sf6cI7Fb", + "management-option": "GZl1Yw", + "interface-id": "pZNGvpNZ", + "interface-description": "jiPT6esm7", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 268, + "resource-version": "1529889840589", + "neutron-network-id": "BTsABqXg", + "neutron-subnet-id": "qjg5eZlk", + "vlan-id-inner": 877, + "l3-interface-ipv4-address": "a64ab58a-26ea-464b-a32d-c30d6bf1d40f-jenkins", + "is-floating": false, + "vlan-id-outer": 31 + }, + { + "l3-interface-ipv4-prefix-length": 395, + "resource-version": "1529889840596", + "neutron-network-id": "v2LUT", + "neutron-subnet-id": "VTknAqDz", + "vlan-id-inner": 205, + "l3-interface-ipv4-address": "0076fd8f-ecb3-4527-b3ee-fee132be8db6-jenkins", + "is-floating": false, + "vlan-id-outer": 461 + } + ] + } + ] + }, + "interface-name": "8806d30d-e5f5-409e-9e9e-9b1c1943058d-jenkins", + "speed-units": "dtp", + "prov-status": "2zeuU", + "interface-description": "hvVs", + "interface-id": "KFxtMnPc5yK0B" + }, + { + "interface-role": "XY4Wle1e0", + "speed-value": "pK4kfeQqTNFh4", + "in-maint": true, + "resource-version": "1529889840619", + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "MsEqgBrWffZ", + "vlans": { + "vlan": [ + { + "vlan-description": "LfyQImV4m0", + "vpn-key": "bYw0P", + "prov-status": "JQCyvJ", + "vlan-id-inner": 566, + "vlan-id-outer": 558, + "orchestration-status": "HIF", + "speed-value": "Ar7CSlrCY", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840646", + "neutron-network-id": "PoZ", + "neutron-subnet-id": "y7SaFxU9te4O", + "l3-interface-ipv6-prefix-length": 631, + "vlan-id-inner": 207, + "is-floating": true, + "l3-interface-ipv6-address": "8466bb52-7984-4792-a37f-b522a0b49f83-jenkins", + "vlan-id-outer": 941 + }, + { + "resource-version": "1529889840652", + "neutron-network-id": "NcYrcVwTCtEH", + "neutron-subnet-id": "370eM", + "l3-interface-ipv6-prefix-length": 137, + "vlan-id-inner": 830, + "is-floating": false, + "l3-interface-ipv6-address": "e291654f-f843-470c-9888-e5ed0e751a8b-jenkins", + "vlan-id-outer": 351 + } + ], + "resource-version": "1529889840629", + "is-ip-unnumbered": false, + "speed-units": "iPOB5", + "vlan-interface": "67dd28da-6b2b-420b-8586-d50ad2832b16-jenkins", + "backdoor-connection": "Sm8BM", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 455, + "resource-version": "1529889840634", + "neutron-network-id": "ILjdNY7FyDFTa", + "neutron-subnet-id": "l5D", + "vlan-id-inner": 499, + "l3-interface-ipv4-address": "5724d3ec-a533-4dda-821d-564fa6f1bd9c-jenkins", + "is-floating": true, + "vlan-id-outer": 863 + }, + { + "l3-interface-ipv4-prefix-length": 129, + "resource-version": "1529889840640", + "neutron-network-id": "ShC4WNzIO", + "neutron-subnet-id": "vg73RjKeCDqdL", + "vlan-id-inner": 947, + "l3-interface-ipv4-address": "3e843120-b62d-4c97-bb41-7f0219db7b14-jenkins", + "is-floating": true, + "vlan-id-outer": 634 + } + ] + }, + { + "vlan-description": "jQcFXNZd", + "vpn-key": "SWZEIY6YS", + "prov-status": "3CGAI", + "vlan-id-inner": 277, + "vlan-id-outer": 527, + "orchestration-status": "zPNrcQLm4uv6P", + "speed-value": "EnMy3", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840682", + "neutron-network-id": "odwHBa91BM1q", + "neutron-subnet-id": "gyUcUX10", + "l3-interface-ipv6-prefix-length": 712, + "vlan-id-inner": 88, + "is-floating": false, + "l3-interface-ipv6-address": "039308d2-d148-427b-b5fd-10674761c44d-jenkins", + "vlan-id-outer": 367 + }, + { + "resource-version": "1529889840676", + "neutron-network-id": "Gza", + "neutron-subnet-id": "pIq", + "l3-interface-ipv6-prefix-length": 466, + "vlan-id-inner": 230, + "is-floating": false, + "l3-interface-ipv6-address": "b88fd72b-daaf-4501-ae0e-03ae6dd908fb-jenkins", + "vlan-id-outer": 881 + } + ], + "resource-version": "1529889840659", + "is-ip-unnumbered": false, + "speed-units": "kCGl", + "vlan-interface": "b765805d-a9ee-4b67-9878-b9ce5393afcd-jenkins", + "backdoor-connection": "3Uj", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 464, + "resource-version": "1529889840670", + "neutron-network-id": "dCij", + "neutron-subnet-id": "JsAH2B", + "vlan-id-inner": 806, + "l3-interface-ipv4-address": "6c72d28b-2068-4421-b434-c91aed94d05f-jenkins", + "is-floating": false, + "vlan-id-outer": 944 + }, + { + "l3-interface-ipv4-prefix-length": 409, + "resource-version": "1529889840664", + "neutron-network-id": "K7Iu55Aeg7", + "neutron-subnet-id": "Szh5oyDazQxx", + "vlan-id-inner": 574, + "l3-interface-ipv4-address": "9bd8b783-fa5f-464f-8c70-c2b7073aaa31-jenkins", + "is-floating": true, + "vlan-id-outer": 901 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "9JOASEc", + "interface-name": "1f2c5777-382d-42a1-95dd-ad46dd3970b6-jenkins", + "allowed-address-pairs": "cj7hTo", + "prov-status": "esrpGpgM66MA", + "macaddr": "ABRk4hv1fYAvm", + "interface-role": "fOx5Ci", + "selflink": "bNOyib", + "in-maint": false, + "admin-status": "aflI2BZ", + "is-port-mirrored": true, + "resource-version": "1529889840695", + "is-ip-unnumbered": false, + "network-name": "W9ikzRrF7mB", + "management-option": "qHHbFL", + "interface-id": "O4z", + "interface-description": "UYX398gN8i" + }, + { + "v6-wan-link-ip": "oSFHmh2phxen", + "interface-name": "17e6f113-b3e2-48a1-bb53-dbaa7318c3f2-jenkins", + "allowed-address-pairs": "B0LqLPi", + "prov-status": "ZMERs2idY", + "macaddr": "iavYQQ8D0", + "interface-role": "LWDdQz9ooY", + "selflink": "NaTAzh6", + "in-maint": false, + "admin-status": "Rwba4Pyl", + "is-port-mirrored": true, + "resource-version": "1529889840701", + "is-ip-unnumbered": false, + "network-name": "qVNOCDe", + "management-option": "mYzH", + "interface-id": "6xOTvBMzb4A", + "interface-description": "xNHFfbZ" + } + ] + }, + "interface-name": "1d6289a3-7dda-42d7-ad36-b8aa82c3527a-jenkins", + "allowed-address-pairs": "SDWi77k0TXOfD", + "prov-status": "ce9dCt", + "macaddr": "pg3ALUfE6T", + "interface-role": "FTsH1RM9", + "selflink": "dWkOVoX", + "in-maint": true, + "admin-status": "Mn3", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840719", + "neutron-network-id": "Ac9ESt", + "neutron-subnet-id": "Z7Lj", + "l3-interface-ipv6-prefix-length": 711, + "vlan-id-inner": 961, + "is-floating": true, + "l3-interface-ipv6-address": "de537e8b-b42c-4543-a680-7b24cd96262c-jenkins", + "vlan-id-outer": 143 + }, + { + "resource-version": "1529889840726", + "neutron-network-id": "n8HSAX", + "neutron-subnet-id": "71QevzBBwqbhw", + "l3-interface-ipv6-prefix-length": 479, + "vlan-id-inner": 845, + "is-floating": true, + "l3-interface-ipv6-address": "b425a520-6389-4382-aa0b-aa2585e8960c-jenkins", + "vlan-id-outer": 57 + } + ], + "is-port-mirrored": false, + "resource-version": "1529889840623", + "is-ip-unnumbered": false, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "NzCY2ZFza", + "vf-vlan-strip": true, + "neutron-network-id": "XVyTFfI", + "vf-broadcast-allow": true, + "vf-mac-anti-spoof-check": true, + "vf-unknown-multicast-allow": true, + "pci-id": "8e034ca2-4f11-4c8e-98cf-d6463986fe4d-jenkins", + "vf-mirrors": "u0FdegnEMsC", + "resource-version": "1529889840690", + "vf-link-status": "CEiqnhy", + "vf-mac-filter": "9QXQosf6", + "vf-insert-stag": true, + "vf-vlan-anti-spoof-check": true, + "vf-unknown-unicast-allow": true + } + ] + }, + "network-name": "ZOxPNuwY", + "management-option": "7NmUPH", + "interface-id": "Hq3BuQ7", + "interface-description": "5Sr3zVcb", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 284, + "resource-version": "1529889840713", + "neutron-network-id": "BGv8mmqI", + "neutron-subnet-id": "55SW", + "vlan-id-inner": 672, + "l3-interface-ipv4-address": "26e40e8b-8e00-43a4-9050-5b9eadc90305-jenkins", + "is-floating": false, + "vlan-id-outer": 946 + }, + { + "l3-interface-ipv4-prefix-length": 623, + "resource-version": "1529889840707", + "neutron-network-id": "voGoxHzyuDW", + "neutron-subnet-id": "PYStGvpuliOY", + "vlan-id-inner": 224, + "l3-interface-ipv4-address": "20ff73f0-4169-43b9-b0c6-ceea0c54a24e-jenkins", + "is-floating": true, + "vlan-id-outer": 913 + } + ] + }, + { + "v6-wan-link-ip": "orgs2voeaiET", + "vlans": { + "vlan": [ + { + "vlan-description": "AE75zek", + "vpn-key": "bka0W79", + "prov-status": "gF8zBYGKLFI1t", + "vlan-id-inner": 620, + "vlan-id-outer": 162, + "orchestration-status": "CzCJsuBNc", + "speed-value": "JQvUCFr", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840757", + "neutron-network-id": "lrYktUQ4B", + "neutron-subnet-id": "87JiirHx", + "l3-interface-ipv6-prefix-length": 244, + "vlan-id-inner": 568, + "is-floating": false, + "l3-interface-ipv6-address": "97f083b3-5cf3-414e-89a6-dd1b20ef06b8-jenkins", + "vlan-id-outer": 201 + }, + { + "resource-version": "1529889840763", + "neutron-network-id": "smMgUDmt", + "neutron-subnet-id": "WfemGm8N5", + "l3-interface-ipv6-prefix-length": 566, + "vlan-id-inner": 43, + "is-floating": false, + "l3-interface-ipv6-address": "4dfd97ec-d11c-40ac-9bc0-a906b50b5095-jenkins", + "vlan-id-outer": 282 + } + ], + "resource-version": "1529889840740", + "is-ip-unnumbered": false, + "speed-units": "zv1", + "vlan-interface": "7006e23b-aa18-491c-94f1-9ccbdb1216c1-jenkins", + "backdoor-connection": "XvPt0D7", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 345, + "resource-version": "1529889840745", + "neutron-network-id": "WkVtQi", + "neutron-subnet-id": "iiE", + "vlan-id-inner": 585, + "l3-interface-ipv4-address": "237dfc24-c581-460f-9e31-608ae9cf07db-jenkins", + "is-floating": false, + "vlan-id-outer": 752 + }, + { + "l3-interface-ipv4-prefix-length": 664, + "resource-version": "1529889840751", + "neutron-network-id": "BMpMnD", + "neutron-subnet-id": "AgrOLB", + "vlan-id-inner": 523, + "l3-interface-ipv4-address": "3ec034d2-5c77-492c-8c63-a2ebda389e5d-jenkins", + "is-floating": true, + "vlan-id-outer": 884 + } + ] + }, + { + "vlan-description": "atAWwI4a3Z9nn", + "vpn-key": "lhN", + "prov-status": "xTREV", + "vlan-id-inner": 687, + "vlan-id-outer": 963, + "orchestration-status": "aZmqJkmVe", + "speed-value": "CxGo", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840793", + "neutron-network-id": "vmmpW", + "neutron-subnet-id": "QmsUCT7Z9", + "l3-interface-ipv6-prefix-length": 869, + "vlan-id-inner": 444, + "is-floating": true, + "l3-interface-ipv6-address": "f694a211-1144-4ac0-8a18-841e4e9b6496-jenkins", + "vlan-id-outer": 307 + }, + { + "resource-version": "1529889840788", + "neutron-network-id": "h3JpE02Qol", + "neutron-subnet-id": "1LP1wI", + "l3-interface-ipv6-prefix-length": 699, + "vlan-id-inner": 695, + "is-floating": true, + "l3-interface-ipv6-address": "d382a20e-6c27-4e3f-a79a-670519ff8091-jenkins", + "vlan-id-outer": 162 + } + ], + "resource-version": "1529889840770", + "is-ip-unnumbered": true, + "speed-units": "3lGVeAq", + "vlan-interface": "4ce368d2-ec9b-4e92-8b7f-031edcec30cc-jenkins", + "backdoor-connection": "3XjveRtVEEBud", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 996, + "resource-version": "1529889840776", + "neutron-network-id": "rXeE0QspfKY", + "neutron-subnet-id": "38sj3w", + "vlan-id-inner": 62, + "l3-interface-ipv4-address": "16a23c8d-1a92-49a9-b03b-09eec176d3eb-jenkins", + "is-floating": true, + "vlan-id-outer": 735 + }, + { + "l3-interface-ipv4-prefix-length": 703, + "resource-version": "1529889840782", + "neutron-network-id": "4AyvZ5hNZ", + "neutron-subnet-id": "1ssFocSaqQo", + "vlan-id-inner": 616, + "l3-interface-ipv4-address": "b96e59ab-e272-4586-857f-b5b6ef8bf3c5-jenkins", + "is-floating": false, + "vlan-id-outer": 857 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "hxz", + "interface-name": "1bf29baf-8a7a-4bef-9e65-60afd4aa4bc5-jenkins", + "allowed-address-pairs": "m5q", + "prov-status": "2jq0q", + "macaddr": "RIoHQVpg", + "interface-role": "AOUF02ImxkTN", + "selflink": "tFX", + "in-maint": false, + "admin-status": "mgaWPPl3y3", + "is-port-mirrored": true, + "resource-version": "1529889840807", + "is-ip-unnumbered": false, + "network-name": "UMXmDlnia43zq", + "management-option": "Vlnc", + "interface-id": "mtfnhl6ONlg40", + "interface-description": "Ow5JhDaD" + }, + { + "v6-wan-link-ip": "8N8zazXz1R", + "interface-name": "76ff110f-6967-4d27-bd9d-4d053f9c344b-jenkins", + "allowed-address-pairs": "bnrD6", + "prov-status": "pPxhpmA0mNMDW", + "macaddr": "IM8RYRdp", + "interface-role": "3gxROfeT", + "selflink": "YcZhmOgXU", + "in-maint": true, + "admin-status": "oSSwcVT7Z", + "is-port-mirrored": false, + "resource-version": "1529889840812", + "is-ip-unnumbered": true, + "network-name": "fqxZ6e1iSI", + "management-option": "e8iCRmtU", + "interface-id": "nYGg", + "interface-description": "7zDWMD0s2" + } + ] + }, + "interface-name": "b654cb26-070e-437a-b04e-7f07d44fdc52-jenkins", + "allowed-address-pairs": "70JS", + "prov-status": "HH4Y", + "macaddr": "m0Xnah2pf1Bpy", + "interface-role": "naRsTm", + "selflink": "fC0AtzLXWIL", + "in-maint": true, + "admin-status": "HAWquxE", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840839", + "neutron-network-id": "Gc3bhBf4bpJ0", + "neutron-subnet-id": "BysFFJ", + "l3-interface-ipv6-prefix-length": 348, + "vlan-id-inner": 170, + "is-floating": true, + "l3-interface-ipv6-address": "0d4500e9-869e-4cb4-9cb4-3819d2c6bbbc-jenkins", + "vlan-id-outer": 383 + }, + { + "resource-version": "1529889840845", + "neutron-network-id": "FZObd3YO", + "neutron-subnet-id": "MJMH2LPtW3N", + "l3-interface-ipv6-prefix-length": 986, + "vlan-id-inner": 907, + "is-floating": true, + "l3-interface-ipv6-address": "2b6c8e63-031b-45cd-b4c4-fe4bc9c73415-jenkins", + "vlan-id-outer": 150 + } + ], + "is-port-mirrored": false, + "resource-version": "1529889840734", + "is-ip-unnumbered": true, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "81VYb1i", + "vf-vlan-strip": false, + "neutron-network-id": "5hrpHU", + "vf-broadcast-allow": true, + "vf-mac-anti-spoof-check": true, + "vf-unknown-multicast-allow": true, + "pci-id": "47a35b64-d6b5-438e-a36e-67527c7adacb-jenkins", + "vf-mirrors": "LVDF81V6wFJFi", + "resource-version": "1529889840801", + "vf-link-status": "j4G9oyAtL8W", + "vf-mac-filter": "loye", + "vf-insert-stag": false, + "vf-vlan-anti-spoof-check": false, + "vf-unknown-unicast-allow": false + } + ] + }, + "network-name": "TTsan6YwMM", + "management-option": "Vm4JdgeI", + "interface-id": "bNt", + "interface-description": "m16u", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 322, + "resource-version": "1529889840827", + "neutron-network-id": "MTRM", + "neutron-subnet-id": "6rhZMmstG4i", + "vlan-id-inner": 134, + "l3-interface-ipv4-address": "f1964d77-7b60-4b52-af29-7e862b35eabc-jenkins", + "is-floating": true, + "vlan-id-outer": 150 + }, + { + "l3-interface-ipv4-prefix-length": 936, + "resource-version": "1529889840833", + "neutron-network-id": "WierCB0r5", + "neutron-subnet-id": "FIhbraamzpd0O", + "vlan-id-inner": 395, + "l3-interface-ipv4-address": "43d2e200-525c-460e-b437-8abd201b6fca-jenkins", + "is-floating": false, + "vlan-id-outer": 688 + } + ] + } + ] + }, + "interface-name": "2ac48363-21fd-485a-8088-c8de995396a3-jenkins", + "speed-units": "lLgzNBkg", + "prov-status": "l299JsuJhY", + "interface-description": "G1C1H", + "interface-id": "w6FY" + } + ] + }, + "equip-model": "e2IFGT", + "in-maint": false, + "p-interfaces": { + "p-interface": [ + { + "equipment-identifier": "fLsqKh", + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "MBw16c7s", + "vlans": { + "vlan": [ + { + "vlan-description": "Fa8BU8", + "vpn-key": "c3PkMMd", + "prov-status": "fJ3DOFSk7", + "vlan-id-inner": 402, + "vlan-id-outer": 34, + "orchestration-status": "eHkM4C", + "speed-value": "zSqye71RT", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889839959", + "neutron-network-id": "Ee9qO6PQ7zi5", + "neutron-subnet-id": "l2A7T", + "l3-interface-ipv6-prefix-length": 684, + "vlan-id-inner": 209, + "is-floating": false, + "l3-interface-ipv6-address": "8914f8ff-e0e7-4835-ad2a-cfa7f0dab948-jenkins", + "vlan-id-outer": 711 + }, + { + "resource-version": "1529889839965", + "neutron-network-id": "eOeaaX", + "neutron-subnet-id": "kv6", + "l3-interface-ipv6-prefix-length": 470, + "vlan-id-inner": 298, + "is-floating": false, + "l3-interface-ipv6-address": "62e3e5aa-adff-48e3-8ec3-fc50ca37864d-jenkins", + "vlan-id-outer": 952 + } + ], + "resource-version": "1529889839942", + "is-ip-unnumbered": true, + "speed-units": "tCdCihW7p4K", + "vlan-interface": "697fa57d-87b6-4ee8-a4cd-83ae7fde814b-jenkins", + "backdoor-connection": "jRx4Vij6fhbmU", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 934, + "resource-version": "1529889839953", + "neutron-network-id": "2augUNUhqiZ", + "neutron-subnet-id": "anWVuz", + "vlan-id-inner": 814, + "l3-interface-ipv4-address": "e72991d7-9397-49fe-8ff2-0b24f5da6601-jenkins", + "is-floating": true, + "vlan-id-outer": 120 + }, + { + "l3-interface-ipv4-prefix-length": 544, + "resource-version": "1529889839947", + "neutron-network-id": "GLBUVmQ", + "neutron-subnet-id": "qJaRGA3xGQ05N", + "vlan-id-inner": 144, + "l3-interface-ipv4-address": "638b0014-0550-4f8f-a182-0f25c7a49094-jenkins", + "is-floating": false, + "vlan-id-outer": 860 + } + ] + }, + { + "vlan-description": "kpjS8p9", + "vpn-key": "K797abgqJPJ", + "prov-status": "VVjAwvGkYn6", + "vlan-id-inner": 145, + "vlan-id-outer": 472, + "orchestration-status": "U4bPZ", + "speed-value": "K3YJXZpVAWlNk", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889839935", + "neutron-network-id": "2M6x", + "neutron-subnet-id": "FtZ6iJ72JPxOp", + "l3-interface-ipv6-prefix-length": 705, + "vlan-id-inner": 360, + "is-floating": true, + "l3-interface-ipv6-address": "d46aee86-d8d1-4f50-95c0-dba97accf2b2-jenkins", + "vlan-id-outer": 91 + }, + { + "resource-version": "1529889839929", + "neutron-network-id": "CfzdGpL", + "neutron-subnet-id": "7NTTSE", + "l3-interface-ipv6-prefix-length": 342, + "vlan-id-inner": 423, + "is-floating": true, + "l3-interface-ipv6-address": "ea3e330f-9868-4cbf-aa99-c57281cdbff8-jenkins", + "vlan-id-outer": 414 + } + ], + "resource-version": "1529889839912", + "is-ip-unnumbered": false, + "speed-units": "eWavRsG", + "vlan-interface": "e270589c-0f82-4213-adff-7edb6eda511a-jenkins", + "backdoor-connection": "ONvEI4XvtvJN", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 384, + "resource-version": "1529889839917", + "neutron-network-id": "kNHGesT", + "neutron-subnet-id": "yA9FTecLecooy", + "vlan-id-inner": 553, + "l3-interface-ipv4-address": "4baec833-d46e-4141-a144-9a69d2995083-jenkins", + "is-floating": false, + "vlan-id-outer": 743 + }, + { + "l3-interface-ipv4-prefix-length": 766, + "resource-version": "1529889839923", + "neutron-network-id": "lY4i8I2h", + "neutron-subnet-id": "nH360LQ", + "vlan-id-inner": 575, + "l3-interface-ipv4-address": "dbce2579-771e-45dd-9eeb-fcfd8abb59a3-jenkins", + "is-floating": false, + "vlan-id-outer": 659 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "VtXT", + "interface-name": "22ba20ad-4f1c-4530-ab9d-fc091051bd84-jenkins", + "allowed-address-pairs": "9mbMpE4l", + "prov-status": "H5E8157", + "macaddr": "BWuWkvhtW8", + "interface-role": "R1EKN", + "selflink": "hUEY5Uw6ZBH", + "in-maint": true, + "admin-status": "DF03UHHd8", + "is-port-mirrored": false, + "resource-version": "1529889839978", + "is-ip-unnumbered": false, + "network-name": "7W2QE34D", + "management-option": "Vkx", + "interface-id": "fGaA", + "interface-description": "i4i" + }, + { + "v6-wan-link-ip": "BC0ksb1bI1EK", + "interface-name": "4c7fe9ad-f5e2-4cc3-8b03-792ae7289154-jenkins", + "allowed-address-pairs": "3oyqp9iyD7", + "prov-status": "C0p5fH6lfcAb", + "macaddr": "WK2Qd", + "interface-role": "w5sQ4P", + "selflink": "6h6qQjMR", + "in-maint": false, + "admin-status": "pYhXCCf83pvO", + "is-port-mirrored": false, + "resource-version": "1529889839984", + "is-ip-unnumbered": true, + "network-name": "GGToGGIWb", + "management-option": "XeKuav", + "interface-id": "zHWzodA2Dy8", + "interface-description": "uvVfwQuN" + } + ] + }, + "interface-name": "7bd89b2e-e723-4d50-a4a2-4a0d1fe69069-jenkins", + "allowed-address-pairs": "JCAK8XN2PNw", + "prov-status": "qlSKW", + "macaddr": "QfkSxy1VuCour", + "interface-role": "nf1rP4iNKUP", + "selflink": "ZSWul0", + "in-maint": false, + "admin-status": "qMVSn68C3QONM", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840003", + "neutron-network-id": "1fuU", + "neutron-subnet-id": "r2oLjsNWsep", + "l3-interface-ipv6-prefix-length": 97, + "vlan-id-inner": 251, + "is-floating": false, + "l3-interface-ipv6-address": "a811422b-b69c-473d-ba0d-6d757d6ebfc7-jenkins", + "vlan-id-outer": 903 + }, + { + "resource-version": "1529889840009", + "neutron-network-id": "0HxL0QUeL", + "neutron-subnet-id": "7mSCgN", + "l3-interface-ipv6-prefix-length": 611, + "vlan-id-inner": 514, + "is-floating": false, + "l3-interface-ipv6-address": "710b2053-4be6-44c7-a2db-833862f398c1-jenkins", + "vlan-id-outer": 441 + } + ], + "is-port-mirrored": true, + "resource-version": "1529889839905", + "is-ip-unnumbered": false, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "9Be4", + "vf-vlan-strip": true, + "neutron-network-id": "OkbLwv534", + "vf-broadcast-allow": true, + "vf-mac-anti-spoof-check": false, + "vf-unknown-multicast-allow": true, + "pci-id": "40672a3c-11df-49d8-ba6c-4266366f81a6-jenkins", + "vf-mirrors": "LHRZR", + "resource-version": "1529889839973", + "vf-link-status": "dL3n6", + "vf-mac-filter": "wTYL", + "vf-insert-stag": true, + "vf-vlan-anti-spoof-check": false, + "vf-unknown-unicast-allow": false + } + ] + }, + "network-name": "9zXzqY2", + "management-option": "zVscglva0VC", + "interface-id": "GND6v7N9BUKdL", + "interface-description": "H2OPAj", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 610, + "resource-version": "1529889839996", + "neutron-network-id": "RYKV1Q", + "neutron-subnet-id": "vr92NIO7V", + "vlan-id-inner": 159, + "l3-interface-ipv4-address": "d9597d04-1bc5-4d62-876f-ed30524bb46f-jenkins", + "is-floating": false, + "vlan-id-outer": 40 + }, + { + "l3-interface-ipv4-prefix-length": 969, + "resource-version": "1529889839990", + "neutron-network-id": "TA6", + "neutron-subnet-id": "f5mhuX2bvOEso", + "vlan-id-inner": 269, + "l3-interface-ipv4-address": "86a9090a-f49c-4734-8a67-8b595e04f647-jenkins", + "is-floating": false, + "vlan-id-outer": 206 + } + ] + }, + { + "v6-wan-link-ip": "JErpT", + "vlans": { + "vlan": [ + { + "vlan-description": "wLNn", + "vpn-key": "hHCbqshyhg", + "prov-status": "Y9420", + "vlan-id-inner": 121, + "vlan-id-outer": 663, + "orchestration-status": "t9S8rSP7p", + "speed-value": "i9cLXv", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840042", + "neutron-network-id": "8jiEnSajGx", + "neutron-subnet-id": "FOVkSB", + "l3-interface-ipv6-prefix-length": 496, + "vlan-id-inner": 558, + "is-floating": false, + "l3-interface-ipv6-address": "e83bed12-5dd7-4d9a-929f-9cf57d728376-jenkins", + "vlan-id-outer": 12 + }, + { + "resource-version": "1529889840047", + "neutron-network-id": "sdOb55dAzQt", + "neutron-subnet-id": "HqtvNrbOW", + "l3-interface-ipv6-prefix-length": 823, + "vlan-id-inner": 62, + "is-floating": true, + "l3-interface-ipv6-address": "49d8a3d2-2f2e-4f2a-a236-2eedabcbae1f-jenkins", + "vlan-id-outer": 341 + } + ], + "resource-version": "1529889840025", + "is-ip-unnumbered": false, + "speed-units": "0yC0mR", + "vlan-interface": "e1159280-5843-412c-9ac6-4b95c1a76f3b-jenkins", + "backdoor-connection": "ZYtmgZrUF6vzS", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 314, + "resource-version": "1529889840029", + "neutron-network-id": "8jHyNtYT7", + "neutron-subnet-id": "9NBJS3AORrVpW", + "vlan-id-inner": 788, + "l3-interface-ipv4-address": "9e56f7a7-1241-4cde-ab06-6166c4208454-jenkins", + "is-floating": true, + "vlan-id-outer": 627 + }, + { + "l3-interface-ipv4-prefix-length": 586, + "resource-version": "1529889840036", + "neutron-network-id": "V5hCkUWfVQNH", + "neutron-subnet-id": "bNHGIvjnK", + "vlan-id-inner": 486, + "l3-interface-ipv4-address": "66eb2cfa-03c5-424d-a992-2e77bf31ddd0-jenkins", + "is-floating": true, + "vlan-id-outer": 230 + } + ] + }, + { + "vlan-description": "PMgsvKp7", + "vpn-key": "jrDeBGUBhtkBC", + "prov-status": "eMkpM1Nq", + "vlan-id-inner": 847, + "vlan-id-outer": 644, + "orchestration-status": "ermPPN", + "speed-value": "mbBs40CypPU4", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840073", + "neutron-network-id": "TYINcC7C55H", + "neutron-subnet-id": "cMVQPrD", + "l3-interface-ipv6-prefix-length": 248, + "vlan-id-inner": 326, + "is-floating": false, + "l3-interface-ipv6-address": "1c054bd3-9e68-48fd-bc6d-e3c3554a7dce-jenkins", + "vlan-id-outer": 110 + }, + { + "resource-version": "1529889840079", + "neutron-network-id": "ZAKaJQsTlgA", + "neutron-subnet-id": "DqmXwxPdIpKQ", + "l3-interface-ipv6-prefix-length": 655, + "vlan-id-inner": 57, + "is-floating": true, + "l3-interface-ipv6-address": "3ae4f973-70d6-4ef3-b006-526e518192b9-jenkins", + "vlan-id-outer": 299 + } + ], + "resource-version": "1529889840055", + "is-ip-unnumbered": false, + "speed-units": "zPO9liNdSX0", + "vlan-interface": "e3d61c90-c6a4-4fcb-93c0-2f568af7ab6f-jenkins", + "backdoor-connection": "jtS6nsN9EBxA", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 982, + "resource-version": "1529889840061", + "neutron-network-id": "2Y8", + "neutron-subnet-id": "vLDZaT", + "vlan-id-inner": 415, + "l3-interface-ipv4-address": "1bb8f77d-8ea7-4893-8c15-a43e3369c67d-jenkins", + "is-floating": false, + "vlan-id-outer": 960 + }, + { + "l3-interface-ipv4-prefix-length": 104, + "resource-version": "1529889840067", + "neutron-network-id": "cSuTgMAjn3r", + "neutron-subnet-id": "sha47kCBHMpo", + "vlan-id-inner": 580, + "l3-interface-ipv4-address": "bcacf13b-0067-420d-953f-e22d84ee3af1-jenkins", + "is-floating": true, + "vlan-id-outer": 687 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "qTVCOp5ygayI0", + "interface-name": "9b13abff-cd24-4bed-8a74-e0e06308a5ce-jenkins", + "allowed-address-pairs": "IVhz", + "prov-status": "olrrQ6Ii", + "macaddr": "2iUmJTqseGCD", + "interface-role": "KFYUN3C", + "selflink": "WZoU", + "in-maint": false, + "admin-status": "VrOUU", + "is-port-mirrored": false, + "resource-version": "1529889840098", + "is-ip-unnumbered": true, + "network-name": "BJX", + "management-option": "lN4SRVrP", + "interface-id": "QL6", + "interface-description": "f0mnjC7ajOATc" + }, + { + "v6-wan-link-ip": "TmD", + "interface-name": "4590458e-0cc9-4e5b-ae64-01410b33eea7-jenkins", + "allowed-address-pairs": "eGq6czv1yR", + "prov-status": "DAwBJiDRwvtCT", + "macaddr": "ZT3YwlcUJE", + "interface-role": "UMD", + "selflink": "yTmWD", + "in-maint": true, + "admin-status": "DxzN", + "is-port-mirrored": false, + "resource-version": "1529889840092", + "is-ip-unnumbered": true, + "network-name": "D3aCxtR7zv", + "management-option": "n3PD", + "interface-id": "iuHyae", + "interface-description": "95TF5HyDT" + } + ] + }, + "interface-name": "a5d58888-7f18-4532-bb9f-cff44f21f764-jenkins", + "allowed-address-pairs": "UMBKF", + "prov-status": "UjcdQWRP", + "macaddr": "mVw", + "interface-role": "UP3MbarHtY5", + "selflink": "srP", + "in-maint": false, + "admin-status": "sgSdzaI", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840123", + "neutron-network-id": "b5qrgF24RBQM", + "neutron-subnet-id": "1516aM83RE", + "l3-interface-ipv6-prefix-length": 841, + "vlan-id-inner": 60, + "is-floating": true, + "l3-interface-ipv6-address": "209a1acb-31bb-454b-a803-1975e14a2b79-jenkins", + "vlan-id-outer": 47 + }, + { + "resource-version": "1529889840117", + "neutron-network-id": "swcjYuHNH1kLF", + "neutron-subnet-id": "6Is", + "l3-interface-ipv6-prefix-length": 341, + "vlan-id-inner": 472, + "is-floating": false, + "l3-interface-ipv6-address": "a1a566eb-0f32-47b1-89c0-97b9e71a5bd1-jenkins", + "vlan-id-outer": 907 + } + ], + "is-port-mirrored": false, + "resource-version": "1529889840017", + "is-ip-unnumbered": false, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "Mu5iYcFtXJO", + "vf-vlan-strip": false, + "neutron-network-id": "1NyV0W", + "vf-broadcast-allow": false, + "vf-mac-anti-spoof-check": false, + "vf-unknown-multicast-allow": false, + "pci-id": "a73b8fbc-51df-4856-a9b1-1fdab27eb1c2-jenkins", + "vf-mirrors": "Xzff495", + "resource-version": "1529889840087", + "vf-link-status": "e3o", + "vf-mac-filter": "weB9RW0kOj", + "vf-insert-stag": true, + "vf-vlan-anti-spoof-check": false, + "vf-unknown-unicast-allow": false + } + ] + }, + "network-name": "EfhznvHgA9sc", + "management-option": "Z3tcQs1t", + "interface-id": "XJFnP9b", + "interface-description": "4EW", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 415, + "resource-version": "1529889840104", + "neutron-network-id": "f6P8vI0vF", + "neutron-subnet-id": "FFTJTHg", + "vlan-id-inner": 118, + "l3-interface-ipv4-address": "4bec049a-3389-4eac-a2aa-366fba5ce65e-jenkins", + "is-floating": true, + "vlan-id-outer": 854 + }, + { + "l3-interface-ipv4-prefix-length": 182, + "resource-version": "1529889840110", + "neutron-network-id": "3DGUAT", + "neutron-subnet-id": "SOsxiS7G", + "vlan-id-inner": 955, + "l3-interface-ipv4-address": "7488692d-58df-41c8-90da-ad740c5ee1c4-jenkins", + "is-floating": true, + "vlan-id-outer": 44 + } + ] + } + ] + }, + "interface-name": "d3ee5116-2a24-4eec-ac0c-5bd4c0d8b591-jenkins", + "prov-status": "KNuQwh3R18IcL", + "interface-role": "n5Ggwbql", + "sriov-pfs": { + "sriov-pf": [ + { + "resource-version": "1529889839900", + "pf-pci-id": "2415ba55-f754-43f3-8549-8367e12292df-jenkins" + } + ] + }, + "selflink": "hlcIkDbgLsj5", + "speed-value": "eZ9SI", + "in-maint": false, + "interface-type": "2d47g", + "port-description": "zSexZ", + "resource-version": "1529889839896", + "inv-status": "GCqk", + "speed-units": "lhQBqM8rf2HXu" + }, + { + "equipment-identifier": "cXNyuU8Lg6TK", + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "kGD", + "vlans": { + "vlan": [ + { + "vlan-description": "rnsklwtzFgYY", + "vpn-key": "TKb", + "prov-status": "xQUPC1z", + "vlan-id-inner": 267, + "vlan-id-outer": 699, + "orchestration-status": "2T0C", + "speed-value": "S4xMNeI", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840210", + "neutron-network-id": "CQWLp", + "neutron-subnet-id": "8MrdSbIszDA", + "l3-interface-ipv6-prefix-length": 707, + "vlan-id-inner": 344, + "is-floating": true, + "l3-interface-ipv6-address": "ba6b944c-05e8-4cb1-959e-b42d5cb70c5a-jenkins", + "vlan-id-outer": 961 + }, + { + "resource-version": "1529889840205", + "neutron-network-id": "Hsw4nXwZLQ", + "neutron-subnet-id": "JW9lhSp55wX", + "l3-interface-ipv6-prefix-length": 325, + "vlan-id-inner": 702, + "is-floating": true, + "l3-interface-ipv6-address": "695e343f-eaea-4a43-bfcb-3d67ec24e090-jenkins", + "vlan-id-outer": 232 + } + ], + "resource-version": "1529889840187", + "is-ip-unnumbered": true, + "speed-units": "JhSHmjEpRvYYm", + "vlan-interface": "1520c860-c608-4696-a2f4-705b65f6046f-jenkins", + "backdoor-connection": "bLB", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 564, + "resource-version": "1529889840199", + "neutron-network-id": "5BczOGn", + "neutron-subnet-id": "eLBW1qhzO3", + "vlan-id-inner": 8, + "l3-interface-ipv4-address": "8496dd5a-3ad7-4557-8dd6-a433db32615d-jenkins", + "is-floating": false, + "vlan-id-outer": 658 + }, + { + "l3-interface-ipv4-prefix-length": 228, + "resource-version": "1529889840192", + "neutron-network-id": "bEA", + "neutron-subnet-id": "Tw9wDLBP", + "vlan-id-inner": 215, + "l3-interface-ipv4-address": "b3482d39-db51-444e-813e-14118a752171-jenkins", + "is-floating": false, + "vlan-id-outer": 805 + } + ] + }, + { + "vlan-description": "n8bWn", + "vpn-key": "oRujs5y", + "prov-status": "SXiegHT", + "vlan-id-inner": 513, + "vlan-id-outer": 296, + "orchestration-status": "INf", + "speed-value": "IIbmsMCpmQ", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840166", + "neutron-network-id": "hyxtLRv", + "neutron-subnet-id": "DA6JkUle", + "l3-interface-ipv6-prefix-length": 76, + "vlan-id-inner": 681, + "is-floating": true, + "l3-interface-ipv6-address": "5a9be38a-b064-40f1-a253-314fded08cdf-jenkins", + "vlan-id-outer": 996 + }, + { + "resource-version": "1529889840171", + "neutron-network-id": "tQQTGDZQj", + "neutron-subnet-id": "XbHEt", + "l3-interface-ipv6-prefix-length": 266, + "vlan-id-inner": 3, + "is-floating": false, + "l3-interface-ipv6-address": "fd2f49c0-8b02-466a-9395-37fb54037f16-jenkins", + "vlan-id-outer": 205 + } + ], + "resource-version": "1529889840149", + "is-ip-unnumbered": false, + "speed-units": "oZUZAVfm64", + "vlan-interface": "710ec65a-0d70-45bc-afc8-6ed029670ec2-jenkins", + "backdoor-connection": "MzNnZT7R5X1pO", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 769, + "resource-version": "1529889840160", + "neutron-network-id": "qTcDiVF2ttvIW", + "neutron-subnet-id": "qIZMW4Jk512a", + "vlan-id-inner": 122, + "l3-interface-ipv4-address": "c3b954f9-3948-4d8b-a894-6eb7cc91f607-jenkins", + "is-floating": true, + "vlan-id-outer": 910 + }, + { + "l3-interface-ipv4-prefix-length": 830, + "resource-version": "1529889840154", + "neutron-network-id": "fBBC", + "neutron-subnet-id": "oXETpyvUOs", + "vlan-id-inner": 91, + "l3-interface-ipv4-address": "cf5af1e4-3f86-4162-9f43-01ef659282d4-jenkins", + "is-floating": false, + "vlan-id-outer": 90 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "McYNumNy4", + "interface-name": "5ab57276-62ba-4fb8-a99a-f4cc64fe1f6b-jenkins", + "allowed-address-pairs": "TVGpW77UF8i", + "prov-status": "FRKsQoZx", + "macaddr": "pyKHSVQTgpnEw", + "interface-role": "lN90EX", + "selflink": "tWy30", + "in-maint": false, + "admin-status": "V6SYyFt", + "is-port-mirrored": false, + "resource-version": "1529889840224", + "is-ip-unnumbered": true, + "network-name": "8b3x", + "management-option": "IiJ4Ex", + "interface-id": "qgH", + "interface-description": "77c" + }, + { + "v6-wan-link-ip": "BxSqzB3k", + "interface-name": "d7193628-997f-4cb8-9772-3ef82d08f7c3-jenkins", + "allowed-address-pairs": "wCxdxBIr", + "prov-status": "GXcP", + "macaddr": "QWcOomv4ZA91", + "interface-role": "l5eAS8RS", + "selflink": "O9RgzEEvn", + "in-maint": true, + "admin-status": "ug2XllNOh", + "is-port-mirrored": false, + "resource-version": "1529889840229", + "is-ip-unnumbered": true, + "network-name": "la6oQgvjY4Z5", + "management-option": "PGNlqnpH", + "interface-id": "8otuL737oC7", + "interface-description": "BqEJ3h" + } + ] + }, + "interface-name": "57964a2a-8d5e-48af-9ac0-089af4d8c968-jenkins", + "allowed-address-pairs": "cwJk0af9GN3", + "prov-status": "CPok", + "macaddr": "0vMHIE", + "interface-role": "Kkyw", + "selflink": "OLNd", + "in-maint": false, + "admin-status": "0dyKQiCmX", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840254", + "neutron-network-id": "uPOdktFWuZjH", + "neutron-subnet-id": "1Vy9Xgxjds", + "l3-interface-ipv6-prefix-length": 431, + "vlan-id-inner": 313, + "is-floating": false, + "l3-interface-ipv6-address": "64e3996d-7b54-4e05-b07e-fb5f2f2966c8-jenkins", + "vlan-id-outer": 972 + }, + { + "resource-version": "1529889840247", + "neutron-network-id": "H29D9C2hy", + "neutron-subnet-id": "sD4RTy", + "l3-interface-ipv6-prefix-length": 800, + "vlan-id-inner": 597, + "is-floating": false, + "l3-interface-ipv6-address": "a80bd4b0-93b9-421d-a7a1-0da425116a1a-jenkins", + "vlan-id-outer": 584 + } + ], + "is-port-mirrored": false, + "resource-version": "1529889840143", + "is-ip-unnumbered": true, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "RNYicsjOHW39H", + "vf-vlan-strip": false, + "neutron-network-id": "pbj6W", + "vf-broadcast-allow": false, + "vf-mac-anti-spoof-check": false, + "vf-unknown-multicast-allow": true, + "pci-id": "ef272d07-37f2-4c42-934f-36b7ea9f40bb-jenkins", + "vf-mirrors": "Oc3iPkPk", + "resource-version": "1529889840218", + "vf-link-status": "fYgzXpWSskZ06", + "vf-mac-filter": "xgRUu", + "vf-insert-stag": true, + "vf-vlan-anti-spoof-check": false, + "vf-unknown-unicast-allow": false + } + ] + }, + "network-name": "qlnWBvDxGh", + "management-option": "zvkV4w", + "interface-id": "doAsSV", + "interface-description": "rS4CU", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 665, + "resource-version": "1529889840235", + "neutron-network-id": "dQO32ksNO1i", + "neutron-subnet-id": "fIRPuXsfHl3RH", + "vlan-id-inner": 899, + "l3-interface-ipv4-address": "5c11ec1e-1d13-4f28-99f6-71fcfdb8f600-jenkins", + "is-floating": true, + "vlan-id-outer": 458 + }, + { + "l3-interface-ipv4-prefix-length": 226, + "resource-version": "1529889840241", + "neutron-network-id": "8C2IrMoc", + "neutron-subnet-id": "6RGtdz", + "vlan-id-inner": 835, + "l3-interface-ipv4-address": "edf54c12-22e9-4ff3-9ae4-1b2ac66e6ac0-jenkins", + "is-floating": false, + "vlan-id-outer": 905 + } + ] + }, + { + "v6-wan-link-ip": "UBtvQADW", + "vlans": { + "vlan": [ + { + "vlan-description": "iK8n", + "vpn-key": "hfhIuxo4", + "prov-status": "P2KBr", + "vlan-id-inner": 952, + "vlan-id-outer": 335, + "orchestration-status": "tVaURe9iKl", + "speed-value": "et4UkQPTAh8N", + "in-maint": false, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840323", + "neutron-network-id": "uCLrTQcl7", + "neutron-subnet-id": "dCqtBvKBlmX", + "l3-interface-ipv6-prefix-length": 613, + "vlan-id-inner": 117, + "is-floating": true, + "l3-interface-ipv6-address": "230b181d-717f-43d7-9bb4-9ad1bf957a91-jenkins", + "vlan-id-outer": 427 + }, + { + "resource-version": "1529889840317", + "neutron-network-id": "yAk", + "neutron-subnet-id": "qXcN", + "l3-interface-ipv6-prefix-length": 396, + "vlan-id-inner": 964, + "is-floating": true, + "l3-interface-ipv6-address": "d525c688-69c3-48df-b4ef-5f5a4c791598-jenkins", + "vlan-id-outer": 640 + } + ], + "resource-version": "1529889840300", + "is-ip-unnumbered": false, + "speed-units": "dSElck", + "vlan-interface": "63adb4ad-4349-4bbf-8e16-62b1d245ac4a-jenkins", + "backdoor-connection": "FdE3", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 418, + "resource-version": "1529889840311", + "neutron-network-id": "qwlh3SoZoj", + "neutron-subnet-id": "7fAwEuJ", + "vlan-id-inner": 753, + "l3-interface-ipv4-address": "99bb541b-7614-4cda-a74f-acebdf50d60e-jenkins", + "is-floating": true, + "vlan-id-outer": 220 + }, + { + "l3-interface-ipv4-prefix-length": 811, + "resource-version": "1529889840305", + "neutron-network-id": "wH1eb", + "neutron-subnet-id": "ncQ8T9", + "vlan-id-inner": 265, + "l3-interface-ipv4-address": "1f80bd34-aa39-400e-b8d9-a858cc4bec25-jenkins", + "is-floating": true, + "vlan-id-outer": 381 + } + ] + }, + { + "vlan-description": "AmUPyMpoz", + "vpn-key": "zS9eKhmKY", + "prov-status": "bW2IFjyyrb", + "vlan-id-inner": 852, + "vlan-id-outer": 777, + "orchestration-status": "sjwcTB", + "speed-value": "1tE5qyCpE", + "in-maint": true, + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840292", + "neutron-network-id": "j866pg4Pm", + "neutron-subnet-id": "6Wyki", + "l3-interface-ipv6-prefix-length": 307, + "vlan-id-inner": 182, + "is-floating": true, + "l3-interface-ipv6-address": "f6d75e58-37d6-4b7e-acb8-2e99f9b4f3c6-jenkins", + "vlan-id-outer": 204 + }, + { + "resource-version": "1529889840286", + "neutron-network-id": "1PkEbG6dYqTfi", + "neutron-subnet-id": "JZh6Tirqre", + "l3-interface-ipv6-prefix-length": 110, + "vlan-id-inner": 655, + "is-floating": true, + "l3-interface-ipv6-address": "36dcfb46-a281-43ec-9f19-57ad77388b86-jenkins", + "vlan-id-outer": 260 + } + ], + "resource-version": "1529889840269", + "is-ip-unnumbered": true, + "speed-units": "Vde", + "vlan-interface": "64aefea8-d550-4328-9528-c6c20ebdcc83-jenkins", + "backdoor-connection": "1IYINR4x", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 807, + "resource-version": "1529889840274", + "neutron-network-id": "IOCxD0A", + "neutron-subnet-id": "fmUBSv4xn", + "vlan-id-inner": 695, + "l3-interface-ipv4-address": "ca68fb8b-47f5-452b-9297-5bb1bf3df3cb-jenkins", + "is-floating": true, + "vlan-id-outer": 320 + }, + { + "l3-interface-ipv4-prefix-length": 412, + "resource-version": "1529889840280", + "neutron-network-id": "825jJkD4", + "neutron-subnet-id": "xm9E", + "vlan-id-inner": 730, + "l3-interface-ipv4-address": "0e19582a-6f8b-4fb5-bf49-b8ee1d94b300-jenkins", + "is-floating": false, + "vlan-id-outer": 796 + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "v6-wan-link-ip": "fRVDB", + "interface-name": "1afbcfe1-fd3f-45e9-8c10-c03687bd155e-jenkins", + "allowed-address-pairs": "pt1w8Myf3CMX", + "prov-status": "aEeKbHcU13Bya", + "macaddr": "W6w1yt4XkZc", + "interface-role": "cqr1D", + "selflink": "0Q1th8cWl", + "in-maint": true, + "admin-status": "FyxEvTkdiprO", + "is-port-mirrored": true, + "resource-version": "1529889840342", + "is-ip-unnumbered": false, + "network-name": "NABSQ7", + "management-option": "4seC3CZ0zmyox", + "interface-id": "vM1", + "interface-description": "hML" + }, + { + "v6-wan-link-ip": "wWDvY3k", + "interface-name": "e1f17f18-2415-4af9-b503-337117a3895a-jenkins", + "allowed-address-pairs": "PoPZQKwe5", + "prov-status": "lrbHN1Glz", + "macaddr": "z1z1PLeAU", + "interface-role": "MZW4", + "selflink": "8MXx36", + "in-maint": true, + "admin-status": "Togx", + "is-port-mirrored": false, + "resource-version": "1529889840336", + "is-ip-unnumbered": false, + "network-name": "IgN0B6", + "management-option": "kYE1hmpQcbv", + "interface-id": "RISQle6r", + "interface-description": "HxiEkqQeZOJ" + } + ] + }, + "interface-name": "55595739-f1c1-40fd-8e02-ed26c8a5a273-jenkins", + "allowed-address-pairs": "Ku1FptLLsb", + "prov-status": "swt3YHhr68", + "macaddr": "SFuEED5Q4", + "interface-role": "j1Szdb", + "selflink": "TWML", + "in-maint": true, + "admin-status": "13qB1qn1IYJHY", + "l3-interface-ipv6-address-list": [ + { + "resource-version": "1529889840360", + "neutron-network-id": "Q2jys", + "neutron-subnet-id": "qfV9kgabkzxT", + "l3-interface-ipv6-prefix-length": 408, + "vlan-id-inner": 856, + "is-floating": false, + "l3-interface-ipv6-address": "33d879a4-cffc-4c9e-b3e3-ca8285904837-jenkins", + "vlan-id-outer": 343 + }, + { + "resource-version": "1529889840367", + "neutron-network-id": "lMt10eoK2AQoa", + "neutron-subnet-id": "1skENPqW", + "l3-interface-ipv6-prefix-length": 320, + "vlan-id-inner": 89, + "is-floating": false, + "l3-interface-ipv6-address": "86fac1bc-375d-4d9f-97e7-1e7bef843039-jenkins", + "vlan-id-outer": 203 + } + ], + "is-port-mirrored": true, + "resource-version": "1529889840262", + "is-ip-unnumbered": false, + "sriov-vfs": { + "sriov-vf": [ + { + "vf-vlan-filter": "ZzMNbVF3sT", + "vf-vlan-strip": false, + "neutron-network-id": "yThOSXDJtt", + "vf-broadcast-allow": false, + "vf-mac-anti-spoof-check": true, + "vf-unknown-multicast-allow": true, + "pci-id": "bf38b0ee-0d9e-4aac-b51d-4e0091063616-jenkins", + "vf-mirrors": "zRC0L4imSH", + "resource-version": "1529889840331", + "vf-link-status": "XMxqQi5QhOrW", + "vf-mac-filter": "bieb3t", + "vf-insert-stag": false, + "vf-vlan-anti-spoof-check": true, + "vf-unknown-unicast-allow": true + } + ] + }, + "network-name": "QLvohj", + "management-option": "fCIqRUOOdh", + "interface-id": "iGkiFK", + "interface-description": "ERxXZI", + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-prefix-length": 153, + "resource-version": "1529889840348", + "neutron-network-id": "JehiIKkHvx", + "neutron-subnet-id": "Mj6TT", + "vlan-id-inner": 333, + "l3-interface-ipv4-address": "c8fe829f-04e1-448b-bebc-bd519b2750c8-jenkins", + "is-floating": true, + "vlan-id-outer": 145 + }, + { + "l3-interface-ipv4-prefix-length": 657, + "resource-version": "1529889840354", + "neutron-network-id": "PYwcY36hEY", + "neutron-subnet-id": "17Hs1AFpT", + "vlan-id-inner": 815, + "l3-interface-ipv4-address": "26764e8a-ad03-46e0-9031-4cbc400b1911-jenkins", + "is-floating": false, + "vlan-id-outer": 435 + } + ] + } + ] + }, + "interface-name": "dfa51737-16a5-4061-a295-bc5e51b31238-jenkins", + "prov-status": "KyURisF3pLj", + "interface-role": "IEn2AUkIiYlh", + "sriov-pfs": { + "sriov-pf": [ + { + "resource-version": "1529889840138", + "pf-pci-id": "99c1731b-7ea5-4af0-9b49-fc447fc02a7f-jenkins" + } + ] + }, + "selflink": "dCPBnieGuf", + "speed-value": "3kz6VhwJf", + "in-maint": true, + "interface-type": "sqBpLbc", + "port-description": "5kzHuoA", + "resource-version": "1529889840133", + "inv-status": "kH1", + "speed-units": "saqVmt9" + } + ] + }, + "resource-version": "1529889839890", + "ram-in-megabytes": 886, + "ipaddress-v4-aim": "14Ku", + "management-option": "qBr", + "internet-topology": "eNTF", + "host-profile": "cd3AI9U2izq6" + } +}
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaapEvents/nos.json b/src/test/resources/test/payloads/dmaapEvents/nos.json new file mode 100644 index 0000000..3efe88f --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/nos.json @@ -0,0 +1,96 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "nos-server", + "top-entity-type": "cloud-region", + "entity-link": "/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/onap-cloud-owner/AAIAIC25/tenants/tenant/tenant-987654321-8991-ps2418/nos-servers/nos-server/nos-server-987654321-8991-ps2418", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "CREATE", + "sequence-number": "0", + "id": "90105aab-78f6-4d83-83b4-48488998a9bd", + "source-name": "SDNC", + "version": "v13", + "timestamp": "20180625-15:29:20:696" + }, + "entity": { + "tenants": { + "tenant": [ + { + "nos-servers": { + "nos-server": [ + { + "nos-server-selflink": "example-nos-server-selflink-val-56832", + "relationship-list": { + "relationship": [ + { + "related-to": "generic-vnf", + "relationship-data": [ + { + "relationship-value": "generic-vnf-987654321-89911-ps2418", + "relationship-key": "generic-vnf.vnf-id" + } + ], + "related-link": "/aai/v13/network/generic-vnfs/generic-vnf/generic-vnf-987654321-89911-ps2418", + "relationship-label": "tosca.relationships.HostedOn", + "related-to-property": [ + { + "property-key": "generic-vnf.vnf-name", + "property-value": "example-vnf-name-val-21594" + } + ] + }, + { + "related-to": "generic-vnf", + "relationship-data": [ + { + "relationship-value": "generic-vnf-987654321-89922-ps2418", + "relationship-key": "generic-vnf.vnf-id" + } + ], + "related-link": "/aai/v13/network/generic-vnfs/generic-vnf/generic-vnf-987654321-89922-ps2418", + "relationship-label": "tosca.relationships.HostedOn", + "related-to-property": [ + { + "property-key": "generic-vnf.vnf-name", + "property-value": "example-vnf-name-val-21594" + } + ] + }, + { + "related-to": "pserver", + "relationship-data": [ + { + "relationship-value": "pserver-987654321-8991-ps2418", + "relationship-key": "pserver.hostname" + } + ], + "related-link": "/aai/v13/cloud-infrastructure/pservers/pserver/pserver-987654321-8991-ps2418", + "relationship-label": "tosca.relationships.HostedOn", + "related-to-property": [ + { + "property-key": "pserver.pserver-name2" + } + ] + } + ] + }, + "in-maint": true, + "vendor": "example-vendor-val-78053", + "resource-version": "1529940560508", + "nos-server-name": "example-nos-server-name-val-4811-nos-server-987654321-8991-ps2418", + "nos-server-id": "nos-server-987654321-8991-ps2418", + "prov-status": "example-prov-status-val-20734" + } + ] + }, + "tenant-id": "tenant-987654321-8991-ps2418", + "tenant-name": "example-tenant-name-val-19302" + } + ] + }, + "cloud-owner": "onap-cloud-owner", + "cloud-region-id": "AAIAIC25" + } +}
\ No newline at end of file diff --git a/src/test/resources/test/payloads/dmaapEvents/vce.json b/src/test/resources/test/payloads/dmaapEvents/vce.json new file mode 100644 index 0000000..adae7ee --- /dev/null +++ b/src/test/resources/test/payloads/dmaapEvents/vce.json @@ -0,0 +1,81 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "vce", + "top-entity-type": "vce", + "entity-link": "/aai/v13/network/vces/vce/vce-987654321-311-ps2418", + "event-type": "AAI-EVENT", + "domain": "uINT1", + "action": "DELETE", + "sequence-number": "0", + "id": "b10f1221-1c3f-42d2-987b-3071818cb613", + "source-name": "FitNesse-Test-ps2418", + "version": "v13", + "timestamp": "20180627-16:35:28:464" + }, + "entity": { + "entitlements": { + "entitlement": [ + { + "resource-version": "1530117237423", + "group-uuid": "group-uuid-2-vce-987654321-311-ps2418", + "resource-uuid": "example-resource-uuid-val-8433" + } + ] + }, + "service-id": "example-service-id-val-62283", + "vnf-id": "vce-987654321-311-ps2418", + "vnf-name2": "example-vnf-name2-val-9403", + "regional-resource-zone": "example-regional-resource-zone-val-78515", + "v6-vce-wan-address": "example-v6-vce-wan-address-val-36157", + "prov-status": "example-prov-status-val-30289", + "operational-status": "example-operational-status-val-52645", + "vpe-id": "example-vpe-id-val-22112", + "equipment-role": "example-equipment-role-val-15655", + "license-key": "example-license-key-val-94096", + "ipv4-oam-address": "example-ipv4-oam-address-val-38828", + "ipv4-loopback0-address": "example-ipv4-loopback0-address-val-22629", + "entitlement-resource-uuid": "example-entitlement-resource-uuid-val-545", + "vnf-type": "example-vnf-type-val-4945", + "orchestration-status": "example-orchestration-status-val-89335", + "licenses": { + "license": [ + { + "resource-version": "1530117237414", + "group-uuid": "group-uuid-vce-987654321-311-ps2418", + "resource-uuid": "example-resource-uuid-val-72009" + } + ] + }, + "heat-stack-id": "example-heat-stack-id-val-97607", + "resource-version": "1530117237387", + "mso-catalog-key": "example-mso-catalog-key-val-27829", + "vnf-name": "example-vnf-name-val-72342", + "port-groups": { + "port-group": [ + { + "interface-role": "example-interface-role-val-37524", + "cvlan-tags": { + "cvlan-tag-entry": [ + { + "resource-version": "1530117237399", + "cvlan-tag": 37491872 + } + ] + }, + "resource-version": "1530117237394", + "heat-stack-id": "example-heat-stack-id-val-90634", + "port-group-name": "example-port-group-name-val-2717", + "neutron-network-id": "example-neutron-network-id-val-27420", + "port-group-id": "example-port-group-id-val-16749", + "mso-catalog-key": "example-mso-catalog-key-val-96458", + "neutron-network-name": "example-neutron-network-name-val-98499", + "switch-name": "example-switch-name-val-78257", + "interface-id": "port-group-interface-id-vce-987654321-311-ps2418", + "orchestration-status": "example-orchestration-status-val-54586" + } + ] + } + } +}
\ No newline at end of file |