Merge "Update schema service to fail to start"
authorJames Forsyth <jf2512@att.com>
Tue, 9 Apr 2019 14:47:59 +0000 (14:47 +0000)
committerGerrit Code Review <gerrit@onap.org>
Tue, 9 Apr 2019 14:47:59 +0000 (14:47 +0000)
aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java
aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java
aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java
aai-core/src/main/java/org/onap/aai/util/AAIConfig.java
aai-core/src/main/java/org/onap/aai/util/AAIConstants.java
docs/release-notes.rst

index 1194dee..656392a 100644 (file)
@@ -23,12 +23,13 @@ package org.onap.aai.serialization.db;
 import com.att.eelf.configuration.EELFLogger;
 import com.att.eelf.configuration.EELFManager;
 import com.google.common.base.CaseFormat;
-import com.google.common.collect.Multimap;
 import org.apache.commons.collections.IteratorUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
-import org.apache.tinkerpop.gremlin.structure.*;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.janusgraph.core.SchemaViolationException;
 import org.javatuples.Triplet;
 import org.onap.aai.concurrent.AaiCallable;
@@ -50,6 +51,7 @@ import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
 import org.onap.aai.introspection.sideeffect.*;
 import org.onap.aai.logging.ErrorLogHelper;
 import org.onap.aai.logging.LogFormatTools;
+import org.onap.aai.logging.LoggingContext;
 import org.onap.aai.logging.StopWatch;
 import org.onap.aai.parsers.query.QueryParser;
 import org.onap.aai.parsers.uri.URIParser;
@@ -61,7 +63,6 @@ import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
 import org.onap.aai.serialization.engines.query.QueryEngine;
-import org.onap.aai.serialization.tinkerpop.TreeBackedVertex;
 import org.onap.aai.setup.SchemaVersion;
 import org.onap.aai.setup.SchemaVersions;
 import org.onap.aai.util.AAIConfig;
@@ -80,15 +81,17 @@ import java.util.*;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
-import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 
 public class DBSerializer {
 
     private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
 
+    private static final String IMPLICIT_DELETE = "Implicit DELETE";
+
+    private static final String MISSING_REQUIRED_NODE_PROPERTY = "Vertex missing required aai-node-type property";
+
     private final TransactionalGraphEngine engine;
     private final String sourceOfTruth;
     private final ModelType introspectionType;
@@ -414,7 +417,57 @@ public class DBSerializer {
         for (Vertex toBeRemoved : processedVertexes) {
             dependentVertexes.remove(toBeRemoved);
         }
-        this.deleteItemsWithTraversal(dependentVertexes);
+
+        // If the dependent vertices are not empty, then with
+        // the current behaviour, it should remove the vertices implicitly
+        // We are updating the code to properly log which call
+        // is doing this so the SE can work with the clients making the call to
+        // tell them not to call this API and can hopefully deprecate this
+        // functionality in the future releases
+        if(!dependentVertexes.isEmpty()){
+
+            LoggingContext.responseDescription(IMPLICIT_DELETE);
+
+            // Find all the deletable vertices from the dependent vertices that should be deleted
+            // So for each of the following dependent vertices,
+            // we will use the edge properties and do the cascade delete
+            List<Vertex> impliedDeleteVertices = this.engine.getQueryEngine().findDeletable(dependentVertexes);
+            int impliedDeleteCount = impliedDeleteVertices.size();
+
+            LOGGER.warn(
+                "For the vertex with id {}, doing an implicit delete on update will delete total of {} vertexes",
+                v.id(),
+                impliedDeleteCount
+            );
+
+            String impliedDeleteLogEnabled = AAIConfig.get(AAIConstants.AAI_IMPLIED_DELETE_LOG_ENABLED, "true");
+
+            int impliedDeleteLogLimit = AAIConfig.getInt(AAIConstants.AAI_IMPLIED_DELETE_LOG_LIMIT, "-1");
+
+            if(impliedDeleteLogLimit == -1){
+                impliedDeleteLogLimit = Integer.MAX_VALUE;
+            }
+
+            // If the logging is enabled for implied delete
+            // then log the payload in the latest format
+            if("true".equals(impliedDeleteLogEnabled) &&
+                impliedDeleteCount <= impliedDeleteLogLimit){
+                for(Vertex vertex : impliedDeleteVertices){
+                    Introspector introspector = null;
+                    try {
+                        introspector = getLatestVersionView(vertex);
+                        if(LOGGER.isInfoEnabled()){
+                            LOGGER.info("Implied delete object in json format {}", introspector.marshal(false));
+                        }
+                    } catch(Exception ex){
+                        LOGGER.warn("Encountered an exception during retrieval of vertex properties with vertex-id {} -> {}", v.id(), LogFormatTools.getStackTop(ex));
+                    }
+                }
+            }
+
+            // After all the appropriate logging, calling the delete to delete the affected vertices
+            this.delete(impliedDeleteVertices);
+        }
 
         this.executePostSideEffects(obj, v);
         return processedVertexes;
@@ -907,9 +960,7 @@ public class DBSerializer {
         String cleanUp = "false";
         boolean nodeOnly = false;
         StopWatch.conditionalStart();
-        Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
-        TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
-        this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
+        this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
         dbTimeMsecs += StopWatch.stopIfStarted();
         return obj;
     }
@@ -1033,7 +1084,16 @@ public class DBSerializer {
         }
 
         List<Object> relationshipObjList = obj.getValue("relationship");
-        String aNodeType = v.property("aai-node-type").value().toString();
+        VertexProperty nodeTypeProperty = v.property(AAIProperties.NODE_TYPE);
+
+        if(!nodeTypeProperty.isPresent()){
+            LoggingContext.responseDescription(MISSING_REQUIRED_NODE_PROPERTY);
+            LOGGER.warn("Not processing the vertex {} because its missing required property aai-node-type", v.id());
+            LoggingContext.remove(LoggingContext.LoggingField.RESPONSE_DESCRIPTION.toString());
+            return null;
+        }
+
+        String aNodeType = nodeTypeProperty.value().toString();
 
         TypeAlphabetizer alphabetizer = new TypeAlphabetizer();
 
@@ -1053,19 +1113,21 @@ public class DBSerializer {
         // from using the edge rules json and get the edge rule out of it
         EdgeRuleQuery.Builder queryBuilder = new EdgeRuleQuery.Builder(aNodeType);
         for (Vertex cousin : cousins) {
-            VertexProperty vertexProperty = cousin.property("aai-node-type");
+            VertexProperty vertexProperty = cousin.property(AAIProperties.NODE_TYPE);
             String bNodeType = null;
             if(vertexProperty.isPresent()){
-                bNodeType = cousin.property("aai-node-type").value().toString();
+                bNodeType = cousin.property(AAIProperties.NODE_TYPE).value().toString();
             } else {
                 // If the vertex is missing the aai-node-type
                 // Then its either a bad vertex or its in the process
                 // of getting deleted so we should ignore these vertexes
+                LoggingContext.responseDescription(MISSING_REQUIRED_NODE_PROPERTY);
                 if(LOGGER.isDebugEnabled()){
                     LOGGER.debug("For the vertex {}, unable to retrieve the aai-node-type", v.id().toString());
                 } else {
                     LOGGER.info("Unable to retrieve the aai-node-type for vertex, for more info enable debug log");
                 }
+                LoggingContext.remove(LoggingContext.LoggingField.RESPONSE_DESCRIPTION.toString());
                 continue;
             }
             if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
@@ -1594,7 +1656,6 @@ public class DBSerializer {
     public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
 
         for (Vertex v : vertexes) {
-            LOGGER.debug("About to delete the vertex with id: " + v.id());
             deleteWithTraversal(v);
         }
 
@@ -1610,10 +1671,39 @@ public class DBSerializer {
         List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
 
         for (Vertex v : results) {
-            LOGGER.warn("Removing vertex " + v.id().toString());
+            LOGGER.debug("Removing vertex {} with label {}", v.id(), v.label());
+            v.remove();
+        }
+        dbTimeMsecs += StopWatch.stopIfStarted();
+    }
+
+    /**
+     * Removes the list of vertexes from the graph
+     * <p>
+     * Current the vertex label will just be vertex but
+     * in the future the aai-node-type property will be replaced
+     * by using the vertex label as when retrieving an vertex
+     * and retrieving an single property on an vertex will pre-fetch
+     * all the properties of that vertex and this is due to the following property
+     * <p>
+     * <code>
+     * query.fast-property=true
+     * </code>
+     * <p>
+     * JanusGraph doesn't provide the capability to override that
+     * at a transaction level and there is a plan to move to vertex label
+     * so it is best to utilize this for now and when the change is applied
+     *
+     * @param vertices - list of vertices to delete from the graph
+     */
+    void delete(List<Vertex> vertices){
+        StopWatch.conditionalStart();
 
+        for (Vertex v : vertices) {
+            LOGGER.debug("Removing vertex {} with label {}", v.id(), v.label());
             v.remove();
         }
+
         dbTimeMsecs += StopWatch.stopIfStarted();
     }
 
index d072db5..94557b0 100644 (file)
@@ -58,7 +58,7 @@ public class GraphTraversalQueryEngine extends QueryEngine {
        /**
         * Instantiates a new graph traversal query engine.
         *
-        * @param graphEngine the graph engine
+        * @param g     graph traversal source to traverse the graph
         */
        public GraphTraversalQueryEngine(GraphTraversalSource g) {
                super(g);
@@ -146,18 +146,47 @@ public class GraphTraversalQueryEngine extends QueryEngine {
         */
        @Override
        public List<Vertex> findDeletable(Vertex start) {
-               @SuppressWarnings("unchecked")
-               GraphTraversal<Vertex, Vertex> pipe = this.g
-                               .V(start).emit(v -> true).repeat(
-                                       __.union(
-                                               __.outE().has(DELETE_OTHER_V.toString(), OUT.toString()).inV(),
-                                               __.inE().has(DELETE_OTHER_V.toString(), IN.toString()).outV()
-                                       )
-                               ).dedup();
+        try {
+            StopWatch.conditionalStart();
+            @SuppressWarnings("unchecked")
+            GraphTraversal<Vertex, Vertex> pipe = this.g
+                    .V(start).emit(v -> true).repeat(
+                        __.union(
+                            __.outE().has(DELETE_OTHER_V.toString(), OUT.toString()).inV(),
+                            __.inE().has(DELETE_OTHER_V.toString(), IN.toString()).outV()
+                        )
+                    ).dedup();
 
-               return pipe.toList();
+            return pipe.toList();
+        } finally {
+            dbTimeMsecs += StopWatch.stopIfStarted();
+        }
        }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Vertex> findDeletable(List<Vertex> startVertexes) {
+        try {
+            StopWatch.conditionalStart();
+            Vertex[] vertices = new Vertex[startVertexes.size()];
+            vertices = startVertexes.toArray(vertices);
+            GraphTraversal<Vertex, Vertex> pipe = this.g
+                .V(vertices).emit(v -> true).repeat(
+                    __.union(
+                        __.outE().has(DELETE_OTHER_V.toString(), OUT.toString()).inV(),
+                        __.inE().has(DELETE_OTHER_V.toString(), IN.toString()).outV()
+                    )
+                ).dedup();
+
+            return pipe.toList();
+        }
+        finally {
+            dbTimeMsecs += StopWatch.stopIfStarted();
+        }
+    }
+
        /**
         * {@inheritDoc}
         */
index 110f862..1e2da4b 100644 (file)
@@ -37,7 +37,7 @@ public abstract class QueryEngine {
        /**
         * Instantiates a new query engine.
         *
-        * @param graphEngine the graph engine
+     * @param g     graph traversal source to traverse the graph
         */
        public QueryEngine (GraphTraversalSource g) {
                this.g = g;
@@ -100,6 +100,15 @@ public abstract class QueryEngine {
         */
        public abstract List<Vertex> findDeletable(Vertex start);
 
+    /**
+     * Find all vertices that should be deleted in a cascade from a delete of start vertexes
+     *
+     * @param   startVertexes   Specifies the list of start vertexes
+     *
+     * @return  the list of vertices to be deleted when start list of vertexes is deleted
+     */
+    public abstract List<Vertex> findDeletable(List<Vertex> startVertexes);
+
        /**
         * Finds the subgraph under start, including cousins as well as start's children/grandchildren/etc.
         * More specifically, this includes start, all its descendants, start's cousins, and start's
index 5b48127..86cb635 100644 (file)
@@ -24,10 +24,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Properties;
-import java.util.Timer;
 import org.onap.aai.logging.LoggingContext;
 import org.onap.aai.logging.LoggingContext.StatusCode;
 
@@ -47,7 +44,7 @@ public class AAIConfig {
        private static final String GLOBAL_PROP_FILE_NAME = AAIConstants.AAI_CONFIG_FILENAME;
        private static Properties serverProps;
     private static boolean propsInitialized = false;
-    
+
     /**
      * Instantiates a new AAI config.
      */
@@ -71,11 +68,11 @@ public class AAIConfig {
                LoggingContext.statusCode(StatusCode.COMPLETE);
 
                LOGGER.info("Initializing AAIConfig");
-               
+
         AAIConfig.getConfigFile();
         AAIConfig.reloadConfig();
-        
-        if (AAIConstants.AAI_NODENAME == null || AAIConstants.AAI_NODENAME == "") {      
+
+        if (AAIConstants.AAI_NODENAME == null || AAIConstants.AAI_NODENAME == "") {
             ErrorLogHelper.logError("AAI_4005", " AAI_NODENAME is not defined");
         } else {
             LOGGER.info("A&AI Server Node Name = " + AAIConstants.AAI_NODENAME);
@@ -99,9 +96,9 @@ public class AAIConfig {
 
         String propFileName = GLOBAL_PROP_FILE_NAME;
         Properties newServerProps = null;
-        
+
         LOGGER.debug("Reloading config from " + propFileName);
-        
+
         try(InputStream is = new FileInputStream(propFileName)) {
             newServerProps = new Properties();
             newServerProps.load(is);
@@ -113,7 +110,7 @@ public class AAIConfig {
                ErrorLogHelper.logError("AAI_4002", " " + propFileName + ". IOException: "+e.getMessage());
         }
     }
-    
+
     /**
      * Gets the.
      *
@@ -142,7 +139,7 @@ public class AAIConfig {
      */
     public static String get(String key) throws AAIException {
        String response = null;
-       
+
        if (key.equals(AAIConstants.AAI_NODENAME)) {
                // Get this from InetAddress rather than the properties file
                String nodeName = getNodeName();
@@ -151,16 +148,16 @@ public class AAIConfig {
                }
                // else get from property file
        }
-       
+
        if (!propsInitialized || (serverProps == null)) {
                reloadConfig();
        }
-       
+
        if ((key.endsWith("password") || key.endsWith("passwd") || key.endsWith("apisecret")) && serverProps.containsKey(key+".x")) {
                String valx = serverProps.getProperty(key+".x");
                return Password.deobfuscate(valx);
        }
-       
+
        if (!serverProps.containsKey(key)) {
                throw new AAIException("AAI_4005", "Property key "+key+" cannot be found");
        } else {
@@ -180,9 +177,19 @@ public class AAIConfig {
      * @throws AAIException the AAI exception
      */
     public static int getInt(String key) throws AAIException{
-       return Integer.valueOf(AAIConfig.get(key));
+       return Integer.parseInt(AAIConfig.get(key));
        }
 
+    /**
+     * Gets the int.
+     *
+     * @param key the key
+     * @return the int
+     */
+    public static int getInt(String key, String value) {
+        return Integer.parseInt(AAIConfig.get(key, value));
+    }
+
        /**
         * Gets the server props.
         *
@@ -191,7 +198,7 @@ public class AAIConfig {
        public static Properties getServerProps() {
                return serverProps;
        }
-       
+
        /**
         * Gets the node name.
         *
@@ -211,8 +218,8 @@ public class AAIConfig {
                }
                return null;
        }
-       
-       
+
+
        /**
         * Check if a null or an Empty string is passed in.
         *
index b735f72..b9fb08f 100644 (file)
@@ -69,6 +69,15 @@ public final class AAIConstants {
 
     public static final String AAI_NODENAME = "aai.config.nodename";
 
+    /*
+     * Logs the objects being deleted when an client deletes objects via implied delete during PUT operation
+     */
+    public static final String AAI_IMPLIED_DELETE_LOG_ENABLED = "aai.implied.delete.log.enabled";
+    /*
+     * Specifies how many objects maximum to log
+     */
+    public static final String AAI_IMPLIED_DELETE_LOG_LIMIT = "aai.implied.delete.log.limit";
+
     public static final String AAI_BULKCONSUMER_LIMIT = "aai.bulkconsumer.payloadlimit";
     public static final String AAI_BULKCONSUMER_OVERRIDE_LIMIT = "aai.bulkconsumer.payloadoverride";
 
index 5153d08..b91bbba 100644 (file)
@@ -6,6 +6,16 @@
 AAI Release Notes
 ==================
 
+Version: 1.3.2
+--------------
+
+:Release Date: 2019-03-31
+
+**Updates**
+
+AAI demo certificates were going to expire before Dublin release, so they've been refreshed to last until 2020.
+
+- `AAI-2282 <https://jira.onap.org/browse/AAI-2282>`_ Update certifcate for Casablanca 3.0.2
 
 Version: 1.3.1
 --------------