Reject doc create requests if index does not exist 11/6111/1
authorFraboni, Gino (gf403a) <gino.fraboni@amdocs.com>
Thu, 20 Jul 2017 17:35:06 +0000 (13:35 -0400)
committergfraboni <gino.fraboni@amdocs.com>
Thu, 20 Jul 2017 17:36:12 +0000 (13:36 -0400)
[AAI-62] Search Data Service should not implicitly create indexes on
document write...

Search Data Service will now explicitly block a document create or
update if the associated index does not already exist in the document
store.

Change-Id: Ie96364da754aa6a2cb554b06f62a7a647181bcce
Signed-off-by: gfraboni <gino.fraboni@amdocs.com>
DOCUMENTS.md
pom.xml
src/main/java/org/openecomp/sa/rest/DocumentApi.java
src/main/java/org/openecomp/sa/searchdbabstraction/elasticsearch/dao/DocumentStoreInterface.java
src/main/java/org/openecomp/sa/searchdbabstraction/elasticsearch/dao/ElasticSearchHttpController.java
src/test/java/org/openecomp/sa/rest/StubEsController.java
src/test/java/org/openecomp/sa/searchdbabstraction/elasticsearch/dao/ElasticSearchHttpControllerTest.java

index ed07543..fcc0949 100644 (file)
@@ -53,6 +53,10 @@ If no _Id_ is provided by the client, then a unique identifier will be generated
 \r
     index - The name of the _Index_ to persist the _Document_ in.\r
 \r
+**Request Header**\r
+\r
+    X-Create-Index  = true = Allow index to be implicitly created if it does not already exist in the document store.\r
+    \r
 **Request Payload**\r
 \r
     Document contents expressed as a JSON object. (see **Syntax**) \r
@@ -93,6 +97,10 @@ _NOTE: If a document id is supplied then it is the responsibility of the client
     index - The name of the _Index_ to persist the Document in.\r
     id    - The identifier to associate with this Document.\r
 \r
+**Request Header**\r
+\r
+    X-Create-Index  = true = Allow index to be implicitly created if it does not already exist in the document store.\r
+    \r
 **Request Payload**\r
 \r
     Document contents expressed as a JSON object. (see **Syntax**) \r
@@ -189,6 +197,7 @@ When performing a _Document_ update, this value must be supplied in the _If-Matc
     Accept          = application/json\r
     X-TransactionId = Unique id set by client (for logging purposes)\r
     X-FromAppId     = Application identifier (for logging purposes)\r
+    X-Create-Index  = true = Allow index to be implicitly created if it does not already exist in the document store.\r
     Content-Type    = application/json   \r
     If-Match        = The ETag value for the document to be updated.\r
 \r
diff --git a/pom.xml b/pom.xml
index 45008e7..9d087ad 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -91,7 +91,8 @@
         <dependency>
           <groupId>org.openecomp.aai.logging-service</groupId>
           <artifactId>common-logging</artifactId>
-          <version>1.0.0-SNAPSHOT</version>
+         <!--<version>1.0.0-SNAPSHOT</version>-->
+          <version>1.0.0</version>
         </dependency>
 
         <!--  Jersey Test Framework. -->
index e3c15a5..7e34d86 100644 (file)
@@ -49,7 +49,8 @@ import javax.ws.rs.core.Response.Status;
 public class DocumentApi {
   private static final String REQUEST_HEADER_RESOURCE_VERSION = "If-Match";
   private static final String RESPONSE_HEADER_RESOURCE_VERSION = "ETag";
-
+  private static final String REQUEST_HEADER_ALLOW_IMPLICIT_INDEX_CREATION = "X-CreateIndex";
+  
   protected SearchServiceApi searchService = null;
 
   private Logger logger = LoggerFactory.getInstance().getLogger(DocumentApi.class.getName());
@@ -92,7 +93,7 @@ public class DocumentApi {
       DocumentStoreDataEntityImpl document = new DocumentStoreDataEntityImpl();
       document.setContent(content);
 
-      DocumentOperationResult result = documentStore.createDocument(index, document);
+      DocumentOperationResult result = documentStore.createDocument(index, document, implicitlyCreateIndex(headers));
       String output = null;
       if (result.getResultCode() >= 200 && result.getResultCode() <= 299) {
         output = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(result.getDocument());
@@ -157,9 +158,9 @@ public class DocumentApi {
 
       DocumentOperationResult result = null;
       if (resourceVersion == null) {
-        result = documentStore.createDocument(index, document);
+        result = documentStore.createDocument(index, document, implicitlyCreateIndex(headers));
       } else {
-        result = documentStore.updateDocument(index, document);
+        result = documentStore.updateDocument(index, document, implicitlyCreateIndex(headers));
       }
 
       String output = null;
@@ -463,6 +464,31 @@ public class DocumentApi {
     }
   }
 
+  
+  /**
+   * Checks the supplied HTTP headers to see if we should allow the underlying document 
+   * store to implicitly create the index referenced in a document PUT or POST if it
+   * does not already exist in the data store.
+   * 
+   * @param headers - The HTTP headers to examine.
+   * 
+   * @return - true if the headers indicate that missing indices should be implicitly created,
+   *           false otherwise.
+   */
+  private boolean implicitlyCreateIndex(HttpHeaders headers) {
+    
+    boolean createIndexIfNotPresent = false;
+    String implicitIndexCreationHeader = 
+        headers.getRequestHeaders().getFirst(REQUEST_HEADER_ALLOW_IMPLICIT_INDEX_CREATION);
+    
+    if( (implicitIndexCreationHeader != null) && (implicitIndexCreationHeader.equals("true")) ) {
+      createIndexIfNotPresent = true;
+    }
+    
+    return createIndexIfNotPresent;
+  }
+  
+  
   private String prepareOutput(ObjectMapper mapper, SearchOperationResult result)
       throws JsonProcessingException {
     StringBuffer output = new StringBuffer();
index a396516..e8dc384 100644 (file)
@@ -39,11 +39,13 @@ public interface DocumentStoreInterface {
 
   public OperationResult deleteIndex(String indexName) throws DocumentStoreOperationException;
 
-  public DocumentOperationResult createDocument(String indexName, DocumentStoreDataEntity document)
-      throws DocumentStoreOperationException;
+  public DocumentOperationResult createDocument(String indexName, 
+                                                DocumentStoreDataEntity document, 
+                                                boolean allowImplicitIndexCreation) throws DocumentStoreOperationException;
 
-  public DocumentOperationResult updateDocument(String indexName, DocumentStoreDataEntity document)
-      throws DocumentStoreOperationException;
+  public DocumentOperationResult updateDocument(String indexName, 
+                                                DocumentStoreDataEntity document,
+                                                boolean allowImplicitIndexCreation) throws DocumentStoreOperationException;
 
   public DocumentOperationResult deleteDocument(String indexName, DocumentStoreDataEntity document)
       throws DocumentStoreOperationException;
index 0e9ff8b..371a483 100644 (file)
@@ -365,8 +365,28 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   }
 
   @Override
-  public DocumentOperationResult createDocument(String indexName, DocumentStoreDataEntity document)
+  public DocumentOperationResult createDocument(String                  indexName, 
+                                                DocumentStoreDataEntity document,
+                                                boolean                 allowImplicitIndexCreation)
       throws DocumentStoreOperationException {
+    
+    if(!allowImplicitIndexCreation) {
+      
+      // Before we do anything, make sure that the specified index actually exists in the
+      // document store - we don't want to rely on ElasticSearch to fail the document
+      // create because it could be configured to implicitly create a non-existent index,
+      // which can lead to hard-to-debug behaviour with queries down the road.
+      OperationResult indexExistsResult = checkIndexExistence(indexName);
+      if ((indexExistsResult.getResultCode() < 200) || (indexExistsResult.getResultCode() >= 300)) {
+  
+        DocumentOperationResult opResult = new DocumentOperationResult();
+        opResult.setResultCode(Status.NOT_FOUND.getStatusCode());
+        opResult.setResult("Document Index '" + indexName + "' does not exist.");
+        opResult.setFailureCause("Document Index '" + indexName + "' does not exist.");
+        return opResult;
+      }
+    }
+    
     if (document.getId() == null || document.getId().isEmpty()) {
       return createDocumentWithoutId(indexName, document);
     } else {
@@ -531,8 +551,28 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   }
 
   @Override
-  public DocumentOperationResult updateDocument(String indexName, DocumentStoreDataEntity document)
+  public DocumentOperationResult updateDocument(String                  indexName, 
+                                                DocumentStoreDataEntity document,
+                                                boolean                 allowImplicitIndexCreation)
       throws DocumentStoreOperationException {
+    
+    if(!allowImplicitIndexCreation) {
+      
+      // Before we do anything, make sure that the specified index actually exists in the
+      // document store - we don't want to rely on ElasticSearch to fail the document
+      // create because it could be configured to implicitly create a non-existent index,
+      // which can lead to hard-to-debug behaviour with queries down the road.
+      OperationResult indexExistsResult = checkIndexExistence(indexName);
+      if ((indexExistsResult.getResultCode() < 200) || (indexExistsResult.getResultCode() >= 300)) {
+  
+        DocumentOperationResult opResult = new DocumentOperationResult();
+        opResult.setResultCode(Status.NOT_FOUND.getStatusCode());
+        opResult.setResult("Document Index '" + indexName + "' does not exist.");
+        opResult.setFailureCause("Document Index '" + indexName + "' does not exist.");
+        return opResult;
+      }
+    }
+    
     DocumentOperationResult opResult = new DocumentOperationResult();
 
     // Initialize operation result with a failure codes / fault string
index f3e5619..8f8a06f 100644 (file)
@@ -60,7 +60,8 @@ public class StubEsController implements DocumentStoreInterface {
 
 
   @Override
-  public OperationResult createIndex(String index, DocumentSchema documentSchema) {
+  public OperationResult createIndex(String         index, 
+                                     DocumentSchema documentSchema) {
 
     // Just return an OK result, with the parameters that we were passed
     // bundled in the response string. This allows unit tests to validate
@@ -91,8 +92,11 @@ public class StubEsController implements DocumentStoreInterface {
   }
 
   @Override
-  public DocumentOperationResult createDocument(String indexName,
-                                                DocumentStoreDataEntity document) throws DocumentStoreOperationException {
+  public DocumentOperationResult createDocument(String                  indexName,
+                                                DocumentStoreDataEntity document,
+                                                boolean                 allowImplicitIndexCreation) 
+    throws DocumentStoreOperationException {
+    
     DocumentOperationResult opResult = buildSampleDocumentOperationResult();
 
     if (indexName.equals(DOES_NOT_EXIST_INDEX)) {
@@ -110,8 +114,11 @@ public class StubEsController implements DocumentStoreInterface {
   }
 
   @Override
-  public DocumentOperationResult updateDocument(String indexName,
-                                                DocumentStoreDataEntity document) throws DocumentStoreOperationException {
+  public DocumentOperationResult updateDocument(String                  indexName,
+                                                DocumentStoreDataEntity document,
+                                                boolean                 allowImplicitIndexCreation) 
+    throws DocumentStoreOperationException {
+    
     DocumentOperationResult opResult = buildSampleDocumentOperationResult();
 
     if (indexName.equals(DOES_NOT_EXIST_INDEX)) {
index 2439f48..f8c6f7f 100644 (file)
@@ -69,7 +69,7 @@ public class ElasticSearchHttpControllerTest {
 
   @Test
   public void testCreateDocument() throws Exception {
-    OperationResult result = elasticSearch.createDocument("test", testDocument);
+    OperationResult result = elasticSearch.createDocument("test", testDocument, false);
     System.out.println(result);
 
     DocumentStoreDataEntityImpl ds = new DocumentStoreDataEntityImpl();
@@ -83,7 +83,7 @@ public class ElasticSearchHttpControllerTest {
   public void testUpdateDocument() throws Exception {
     testDocument.setEdgeTagQueryEntityFieldValue("567890");
 
-    OperationResult result = elasticSearch.updateDocument("test", testDocument);
+    OperationResult result = elasticSearch.updateDocument("test", testDocument, false);
     System.out.println(result);
 
     result = elasticSearch.getDocument("test", testDocument);
@@ -110,7 +110,7 @@ public class ElasticSearchHttpControllerTest {
       doc.setSearchTagIDs("" + i);
       doc.setSearchTags("service-instance-id");
 
-      OperationResult result = elasticSearch.createDocument("test", doc);
+      OperationResult result = elasticSearch.createDocument("test", doc, false);
       System.out.println(result);
     }
   }
@@ -142,7 +142,7 @@ public class ElasticSearchHttpControllerTest {
     doc.setSearchTagIDs("321");
     doc.setSearchTags("service-instance-id");
 
-    OperationResult result = elasticSearch.createDocument("test", doc);
+    OperationResult result = elasticSearch.createDocument("test", doc, false);
     System.out.println(result);
   }