* 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=========================================================
*/
* Fetch list of Transactions which are in non-terminal state i.e. ACCEPTED or RECEIVED for particular TargetId.
* @param record Transactions object from which TargetId and StartTime is extracted to fetch list of in progress
* requests which APPC received before the current request.
+ * @param interval Number of hours - Time window to consider requests as being in progress
* @return List of Transactions in non terminal state.
* @throws APPCException
*/
- List<TransactionRecord> getInProgressRequests(TransactionRecord record) throws APPCException;
+ List<TransactionRecord> getInProgressRequests(TransactionRecord record, int interval) throws APPCException;
/**
* Checks whether the incoming request is duplicate.
* 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=========================================================
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.time.temporal.ChronoUnit;
import static org.onap.appc.transactionrecorder.objects.TransactionConstants.TRANSACTION_ATTRIBUTES.*;
import static org.onap.appc.transactionrecorder.objects.TransactionConstants.*;
}
@Override
- public List<TransactionRecord> getInProgressRequests(TransactionRecord record) throws APPCException {
+ public List<TransactionRecord> getInProgressRequests(TransactionRecord record, int interval) throws APPCException {
- final String IN_PROGRESS_REQUESTS_QUERY = "SELECT * FROM " +
+ String IN_PROGRESS_REQUESTS_QUERY = "SELECT * FROM " +
TransactionConstants.TRANSACTIONS + WHERE +
TARGET_ID + " = ? AND " +
STATE.getColumnName() + " IN (?,?) AND " +
START_TIME.getColumnName() + " < ?";
ArrayList<String> inProgressQueryParams = new ArrayList<>();
+ Instant window = record.getStartTime().minus(interval, ChronoUnit.HOURS);
inProgressQueryParams.add(record.getTargetId());
inProgressQueryParams.add(RequestStatus.RECEIVED.name());
inProgressQueryParams.add(RequestStatus.ACCEPTED.name());
inProgressQueryParams.add(dateToStringConverterMillis(record.getStartTime()));
+ if (interval > 0) {
+ IN_PROGRESS_REQUESTS_QUERY += " AND " + START_TIME.getColumnName() + " > ? ";
+ inProgressQueryParams.add(dateToStringConverterMillis(window));
+ }
try (CachedRowSet rowSet = dbLibService.getData(IN_PROGRESS_REQUESTS_QUERY, inProgressQueryParams, SCHEMA)) {
List<TransactionRecord> inProgressRecords = new ArrayList<>();
* 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=========================================================
*/
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
input.setStartTime(Instant.now());
Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
inMemoryExecutionWithResultSet(invocation.getArguments()));
- Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input).size());
+ Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input,0).size());
+
+ }
+
+ @Test
+ public void testGetInProgressRequestsWithinTimeInterval() throws SQLException, APPCException {
+ TransactionRecord record1 = prepareTransactionsInput();
+ record1.setStartTime(Instant.now().minus(4,ChronoUnit.HOURS));
+ insertRecord(record1);
+ TransactionRecord input = prepareTransactionsInput();
+ input.setStartTime(Instant.now());
+ Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
+ inMemoryExecutionWithResultSet(invocation.getArguments()));
+ List<TransactionRecord> aList= transactionRecorderImpl.getInProgressRequests(input,12);
+ Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input,12).size());
}
* 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=========================================================
*/
private RequestValidationPolicy requestValidationPolicy;
private RestClientInvoker client;
private String path;
+ private int transactionWindowInterval=0;
static final String SCOPE_OVERLAP_ENDPOINT = "appc.LCM.scopeOverlap.endpoint";
static final String ODL_USER = "appc.LCM.provider.user";
static final String ODL_PASS = "appc.LCM.provider.pass";
-
+ static final String TRANSACTION_WINDOW_HOURS = "appc.inProgressTransactionWindow.hours";
+
public void initialize() throws APPCException {
logger.info("Initializing RequestValidatorImpl.");
String endpoint = null;
String user = null;
String pass =null;
+ String transactionWindow = null;
+
Properties properties = configuration.getProperties();
if (properties != null) {
endpoint = properties.getProperty(SCOPE_OVERLAP_ENDPOINT);
user = properties.getProperty(ODL_USER);
pass = properties.getProperty(ODL_PASS);
+ transactionWindow = properties.getProperty(TRANSACTION_WINDOW_HOURS);
}
if (endpoint == null) {
String message = "End point is not defined for scope over lap service in appc.properties.";
return;
}
+ if (StringUtils.isNotBlank(transactionWindow)) {
+ logger.info("RequestValidatorImpl::TransactionWindow defined !!!");
+ try {
+ transactionWindowInterval = Integer.parseInt(transactionWindow);
+ }
+ catch (NumberFormatException e) {
+ String message = "RequestValidatorImpl:::Error parsing transaction window interval!";
+ logger.error(message, e);
+ throw new APPCException(message);
+ }
+ }
+
try {
URL url = new URL(endpoint);
client = new RestClientInvoker(url);
client.setAuthentication(user, pass);
- path = url.getPath();
-
+ path = url.getPath();
+
} catch (MalformedURLException e) {
String message = "Invalid endpoint " + endpoint;
logger.error(message, e);
return;
}
+ List<TransactionRecord> inProgressTransactionsAll = transactionRecorder
+ .getInProgressRequests(runtimeContext.getTransactionRecord(),0);
List<TransactionRecord> inProgressTransactions = transactionRecorder
- .getInProgressRequests(runtimeContext.getTransactionRecord());
+ .getInProgressRequests(runtimeContext.getTransactionRecord(),transactionWindowInterval);
+
+ long inProgressTransactionsAllCount = inProgressTransactionsAll.size();
+ long inProgressTransactionsRelevant = inProgressTransactions.size();
logger.debug("In progress requests " + inProgressTransactions.toString());
+ if ( inProgressTransactions.isEmpty()){ //No need to check for scope overlap
+ return;
+ }
+
+ logInProgressTransactions(inProgressTransactions,inProgressTransactionsAllCount,
+ inProgressTransactionsRelevant );
+
Long exclusiveRequestCount = inProgressTransactions.stream()
.filter(record -> record.getMode().equals(Flags.Mode.EXCLUSIVE.name())).count();
if (exclusiveRequestCount > 0) {
ObjectMapper objectMapper = new ObjectMapper();
ScopeOverlapModel scopeOverlapModel = getScopeOverlapModel(requestContext, inProgressTransactions);
// Added for change in interface for action level
-
+
JsonNode jsonObject = objectMapper.valueToTree(scopeOverlapModel);
return jsonObject;
Request request = new Request();
Date date = new Date();
- request.setRequestID("RequestId-ScopeOverlap " + date.toString());
+ request.setRequestID("RequestId-ScopeOverlap " + date.toString());
request.setAction("isScopeOverlap");
ObjectMapper objectMapper = new ObjectMapper();
JsonNode json = objectMapper.valueToTree(requestData);
Input input = new Input();
input.setRequest(request);
scopeOverlapModel.setInput(input);
-
+
return scopeOverlapModel;
}
}
return workflowRequest;
}
+
+ public String logInProgressTransactions(List<TransactionRecord> inProgressTransactions,
+ long inProgressTransactionsAllCount, long inProgressTransactionsRelevant) {
+ if (inProgressTransactionsAllCount > inProgressTransactionsRelevant) {
+ logger.info("Found Stale Transactions! Ignoring Stale Transactions for target, only considering "
+ + "transactions within the last " + transactionWindowInterval + " hours as transactions in-progress");
+ }
+ String logMsg="";
+ for (TransactionRecord tr: inProgressTransactions) {
+ logMsg = ("In Progress transaction for Target ID - "+ tr.getTargetId()
+ + " in state " + tr.getRequestState()
+ + " with Start time " + tr.getStartTime().toString()
+ + " for more than configurable time period " + transactionWindowInterval
+ + " hours [transaction details - Request ID - " + tr.getTransactionId()
+ + ", Service Instance Id -" + tr.getServiceInstanceId()
+ + ", Vserver_id - " + tr.getVserverId()
+ + ", VNFC_name - "+ tr.getVnfcName()
+ + ", VF module Id - " + tr.getVfModuleId()
+ + " Start time " + tr.getStartTime().toString()
+ + "]" );
+ }
+ return logMsg;
+
+ }
}
package org.onap.appc.requesthandler.impl;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.MalformedURLException;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
+import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.entity.BasicHttpEntity;
import org.onap.appc.domainmodel.lcm.Flags;
import org.onap.appc.domainmodel.lcm.Flags.Mode;
import org.onap.appc.domainmodel.lcm.RequestContext;
+import org.onap.appc.domainmodel.lcm.RequestStatus;
import org.onap.appc.domainmodel.lcm.ResponseContext;
import org.onap.appc.domainmodel.lcm.RuntimeContext;
import org.onap.appc.domainmodel.lcm.TransactionRecord;
}
- @Test(expected = RequestValidationException.class)
+ @Test (expected = RequestValidationException.class)
public void testValidateRequest() throws Exception {
RuntimeContext runtimeContext = createRequestValidatorInput();
logger = Mockito.spy(EELFManager.getInstance().getLogger(LCMStateManager.class));
lcmStateManager.enableLCMOperations();
transactionRecorder = Mockito.mock(TransactionRecorder.class);
Mockito.when(transactionRecorder.isTransactionDuplicate(anyObject())).thenReturn(false);
+ List<TransactionRecord> transactionRecordList = new ArrayList<TransactionRecord>(1);
TransactionRecord transactionRecord = new TransactionRecord();
transactionRecord.setMode(Mode.EXCLUSIVE);
+ transactionRecord.setStartTime(Instant.now().minus(5, ChronoUnit.HOURS));
+ transactionRecord.setRequestState(RequestStatus.ACCEPTED);
runtimeContext.setTransactionRecord(transactionRecord);
+ transactionRecordList.add(transactionRecord);
+ Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class),Mockito.any(int.class)))
+ .thenReturn(transactionRecordList);
impl.setTransactionRecorder(transactionRecorder);
WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(true, true);
WorkFlowManager workflowManager = Mockito.mock(WorkFlowManagerImpl.class);
List<TransactionRecord> transactionRecordList = new ArrayList<TransactionRecord>(1);
TransactionRecord inProgressTransaction = new TransactionRecord();
inProgressTransaction.setMode(Mode.EXCLUSIVE);
+ inProgressTransaction.setStartTime(Instant.now().minus(5, ChronoUnit.HOURS));
+ inProgressTransaction.setRequestState(RequestStatus.ACCEPTED);
transactionRecordList.add(inProgressTransaction);
- Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class)))
+ Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class),Mockito.any(int.class)))
.thenReturn(transactionRecordList);
runtimeContext.setTransactionRecord(inProgressTransaction);
impl.setTransactionRecorder(transactionRecorder);
RuntimeContext runtimeContext = createRequestValidatorInput();
lcmStateManager.enableLCMOperations();
transactionRecorder = Mockito.mock(TransactionRecorder.class);
- Mockito.when(transactionRecorder.isTransactionDuplicate(anyObject())).thenReturn(false);
+
List<TransactionRecord> transactionRecordList = new ArrayList<TransactionRecord>(1);
TransactionRecord inProgressTransaction = new TransactionRecord();
inProgressTransaction.setMode(Mode.NORMAL);
inProgressTransaction.setOperation(VNFOperation.ActionStatus);
+ inProgressTransaction.setRequestState(RequestStatus.ACCEPTED);
+ inProgressTransaction.setStartTime(Instant.now().minus(48, ChronoUnit.HOURS));
transactionRecordList.add(inProgressTransaction);
- runtimeContext.setTransactionRecord(inProgressTransaction);
- Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class)))
- .thenReturn(transactionRecordList);
+ Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class),Mockito.any(int.class)))
+ .thenReturn(transactionRecordList);
+ Mockito.when(transactionRecorder.isTransactionDuplicate(anyObject())).thenReturn(false);
impl.setTransactionRecorder(transactionRecorder);
- WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(true, true);
+ runtimeContext.setTransactionRecord(inProgressTransaction);
WorkFlowManager workflowManager = Mockito.mock(WorkFlowManagerImpl.class);
+ WorkflowExistsOutput workflowExistsOutput = Mockito.spy(new WorkflowExistsOutput(true, true));
Mockito.when(workflowManager.workflowExists(Mockito.any(WorkflowRequest.class)))
.thenReturn(workflowExistsOutput);
impl.setWorkflowManager(workflowManager);
impl.validateRequest(runtimeContext);
}
+ @Test
+ public void testLogInProgressTransactions() {
+ ArrayList<TransactionRecord> trArray = new ArrayList();
+ TransactionRecord tr = new TransactionRecord();
+ tr.setRequestState(RequestStatus.ACCEPTED);
+ tr.setStartTime(Instant.now().minus(48, ChronoUnit.HOURS));
+ tr.setTargetId("Vnf001");
+ trArray.add(tr);
+ String loggedMessage = impl.logInProgressTransactions(trArray, 1, 1);
+ String partMessage = "In Progress transaction for Target ID - Vnf001 in state ACCEPTED";
+ assertTrue(StringUtils.contains(loggedMessage, partMessage));
+ }
+
private RuntimeContext createRequestValidatorInput() {
return createRequestHandlerRuntimeContext("VSCP", "{\"request-id\":\"request-id\"}");
}