aboutsummaryrefslogtreecommitdiffstats
path: root/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java')
-rw-r--r--controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java1504
1 files changed, 793 insertions, 711 deletions
diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java
index ba2df3358..7c900249c 100644
--- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java
+++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopOperationManager.java
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* controlloop operation manager
* ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 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.
@@ -54,715 +54,797 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ControlLoopOperationManager implements Serializable {
- private static final long serialVersionUID = -3773199283624595410L;
- private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
-
- private static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
- private static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
- private static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
-
- @Override
- public String toString() {
- return "ControlLoopOperationManager [onset=" + (onset != null ? onset.getRequestID() : "null") + ", policy="
- + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts
- + ", policyResult=" + policyResult
- + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
- + "]";
- }
-
- //
- // These properties are not changeable, but accessible
- // for Drools Rule statements.
- //
- public final ControlLoopEvent onset;
- public final transient Policy policy;
-
- //
- // Properties used to track the Operation
- //
- private int attempts = 0;
- private transient Operation currentOperation = null;
- private LinkedList<Operation> operationHistory = new LinkedList<>();
- private PolicyResult policyResult = null;
- private ControlLoopEventManager eventManager = null;
- private String targetEntity;
-
- public ControlLoopEventManager getEventManager() {
- return eventManager;
- }
-
- public void setEventManager(ControlLoopEventManager eventManager) {
- this.eventManager = eventManager;
- }
-
- public String getTargetEntity() {
- return this.targetEntity;
- }
-
- //
- // Internal class used for tracking
- //
- private class Operation {
- private ControlLoopOperation clOperation = new ControlLoopOperation();
- private PolicyResult policyResult = null;
- private int attempt = 0;
-
- @Override
- public String toString() {
- return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + clOperation
- + "]";
- }
- }
-
- private String guardApprovalStatus = "NONE";//"NONE", "PERMIT", "DENY"
- private transient Object operationRequest;
-
- public Object getOperationRequest() {
- return operationRequest;
- }
-
- public String getGuardApprovalStatus() {
- return guardApprovalStatus;
- }
- public void setGuardApprovalStatus(String guardApprovalStatus) {
- this.guardApprovalStatus = guardApprovalStatus;
- }
-
- public String getTarget(Policy policy) throws ControlLoopException, AAIException {
- if (policy.getTarget() == null) {
- throw new ControlLoopException("The target is null");
- }
-
- if (policy.getTarget().getType() == null) {
- throw new ControlLoopException("The target type is null");
- }
-
- switch(policy.getTarget().getType()) {
- case PNF:
- throw new ControlLoopException("PNF target is not supported");
- case VM:
- case VNF:
- VirtualControlLoopEvent virtualOnset = (VirtualControlLoopEvent) this.onset;
- if (this.onset.getTarget().equalsIgnoreCase(VSERVER_VSERVER_NAME)) {
- return virtualOnset.getAAI().get(VSERVER_VSERVER_NAME);
- }
- else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_ID)) {
- return virtualOnset.getAAI().get(GENERIC_VNF_VNF_ID);
- }
- else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_NAME)) {
- /*
- * If the onset is enriched with the vnf-id,
- * we don't need an A&AI response
- */
- if (virtualOnset.getAAI().containsKey(GENERIC_VNF_VNF_ID)) {
- return virtualOnset.getAAI().get(GENERIC_VNF_VNF_ID);
- }
-
- /*
- * If the vnf-name was retrieved from the onset then the vnf-id
- * must be obtained from the event manager's A&AI GET query
- */
- String vnfId = this.eventManager.getVnfResponse().getVnfID();
- if (vnfId == null) {
- throw new AAIException("No vnf-id found");
- }
- return vnfId;
- }
- throw new ControlLoopException("Target does not match target type");
- default:
- throw new ControlLoopException("The target type is not supported");
- }
- }
-
- public ControlLoopOperationManager(ControlLoopEvent onset, Policy policy, ControlLoopEventManager em) throws ControlLoopException, AAIException {
- this.onset = onset;
- this.policy = policy;
- this.guardApprovalStatus = "NONE";
- this.eventManager = em;
- this.targetEntity = getTarget(policy);
-
- //
- // Let's make a sanity check
- //
- switch (policy.getActor()) {
- case "APPC":
- if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
- /*
- * The target vnf-id may not be the same as the source vnf-id
- * specified in the yaml, the target vnf-id is retrieved by
- * a named query to A&AI.
- */
- String targetVnf = AppcLcmActorServiceProvider.vnfNamedQuery( policy.getTarget().getResourceID(), this.targetEntity);
- this.targetEntity = targetVnf;
- }
- break;
- case "SO":
- break;
- case "VFC":
- break;
- default:
- throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor.");
- }
- }
-
- public Object startOperation(/*VirtualControlLoopEvent*/ControlLoopEvent onset) throws ControlLoopException{
- verifyOperatonCanRun();
-
- //
- // Setup
- //
- this.policyResult = null;
- Operation operation = new Operation();
- operation.attempt = ++this.attempts;
- operation.clOperation.setActor(this.policy.getActor());
- operation.clOperation.setOperation(this.policy.getRecipe());
- operation.clOperation.setTarget(this.policy.getTarget().toString());
- operation.clOperation.setSubRequestId(Integer.toString(operation.attempt));
- //
- // Now determine which actor we need to construct a request for
- //
- switch (policy.getActor()) {
- case "APPC":
- /*
- * If the recipe is ModifyConfig, a legacy APPC
- * request is constructed. Otherwise an LCMRequest
- * is constructed.
- */
- this.currentOperation = operation;
- if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
- this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
- operation.clOperation, this.policy, this.targetEntity);
- }
- else {
- this.operationRequest = AppcLcmActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
- operation.clOperation, this.policy, this.targetEntity);
- }
- //
- // Save the operation
- //
-
- return operationRequest;
- case "SO":
- SOActorServiceProvider soActorSP = new SOActorServiceProvider();
- this.operationRequest = soActorSP.constructRequest((VirtualControlLoopEvent)onset, operation.clOperation, this.policy);
-
- // Save the operation
- this.currentOperation = operation;
-
- if (this.operationRequest == null) {
- this.policyResult = PolicyResult.FAILURE;
- }
-
- return operationRequest;
- case "VFC":
- this.operationRequest = VFCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.eventManager.getVnfResponse());
- this.currentOperation = operation;
- if (this.operationRequest == null) {
- this.policyResult = PolicyResult.FAILURE;
- }
- return operationRequest;
- default:
- throw new ControlLoopException("invalid actor " + policy.getActor() + " on policy");
- }
- }
-
- public PolicyResult onResponse(Object response) {
- //
- // Which response is it?
- //
- if (response instanceof Response) {
- //
- // Cast APPC response and handle it
- //
- return onResponse((Response) response);
- }
- else if (response instanceof LCMResponseWrapper) {
- //
- // Cast LCM response and handle it
- //
- return onResponse((LCMResponseWrapper) response);
- }
- else if (response instanceof SOResponseWrapper) {
- //
- // Cast SO response and handle it
- //
- return onResponse((SOResponseWrapper) response);
- }
- else if (response instanceof VFCResponse) {
- //
- // Cast VFC response and handle it
- //
- return onResponse((VFCResponse) response);
- }
- else {
- return null;
- }
- }
-
- /**
- * This method handles operation responses from APPC
- * @param appcResponse the APPC response
- * @return The result of the response handling
- */
- private PolicyResult onResponse(Response appcResponse) {
- //
- // Determine which subrequestID (ie. attempt)
- //
- Integer operationAttempt = null;
- try {
- operationAttempt = Integer.parseInt(appcResponse.getCommonHeader().getSubRequestID());
- } catch (NumberFormatException e) {
- //
- // We cannot tell what happened if this doesn't exist
- //
- this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION);
- return PolicyResult.FAILURE_EXCEPTION;
- }
- //
- // Sanity check the response message
- //
- if (appcResponse.getStatus() == null) {
- //
- // We cannot tell what happened if this doesn't exist
- //
- this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status field (it was null).", PolicyResult.FAILURE_EXCEPTION);
- return PolicyResult.FAILURE_EXCEPTION;
- }
- //
- // Get the Response Code
- //
- ResponseCode code = ResponseCode.toResponseCode(appcResponse.getStatus().getCode());
- if (code == null) {
- //
- // We are unaware of this code
- //
- this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.", PolicyResult.FAILURE_EXCEPTION);
- return PolicyResult.FAILURE_EXCEPTION;
- }
- //
- // Ok, let's figure out what APP-C's response is
- //
- switch (code) {
- case ACCEPT:
- //
- // This is good, they got our original message and
- // acknowledged it.
- //
- // Is there any need to track this?
- //
- return null;
- case ERROR:
- case REJECT:
- //
- // We'll consider these two codes as exceptions
- //
- this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(), PolicyResult.FAILURE_EXCEPTION);
- if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
- return null;
- }
- return PolicyResult.FAILURE_EXCEPTION;
- case SUCCESS:
- //
- //
- //
- this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(), PolicyResult.SUCCESS);
- if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
- return null;
- }
- return PolicyResult.SUCCESS;
- case FAILURE:
- //
- //
- //
- this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(), PolicyResult.FAILURE);
- if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
- return null;
- }
- return PolicyResult.FAILURE;
- default:
- return null;
- }
- }
-
- /**
- * This method handles operation responses from LCM
- * @param dmaapResponse the LCM response
- * @return The result of the response handling
- */
- private PolicyResult onResponse(LCMResponseWrapper dmaapResponse) {
- /*
- * Parse out the operation attempt using the subrequestid
- */
- Integer operationAttempt = AppcLcmActorServiceProvider.parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
- if (operationAttempt == null) {
- this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION);
- }
-
- /*
- * Process the APPCLCM response to see what PolicyResult
- * should be returned
- */
- AbstractMap.SimpleEntry<PolicyResult, String> result = AppcLcmActorServiceProvider.processResponse(dmaapResponse);
-
- if (result.getKey() != null) {
- this.completeOperation(operationAttempt, result.getValue(), result.getKey());
- if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
- return null;
- }
- return result.getKey();
- }
- return null;
- }
-
- /**
- * This method handles operation responses from SO
- * @param msoResponse the SO response
- * @return The result of the response handling
- */
- private PolicyResult onResponse(SOResponseWrapper msoResponse) {
- switch (msoResponse.getSoResponse().getHttpResponseCode()) {
- case 200:
- case 202:
- //
- // Consider it as success
- //
- this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + " Success", PolicyResult.SUCCESS);
- if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
- return null;
- }
- return PolicyResult.SUCCESS;
- default:
- //
- // Consider it as failure
- //
- this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + " Failed", PolicyResult.FAILURE);
- if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
- return null;
- }
- return PolicyResult.FAILURE;
- }
- }
-
- /**
- * This method handles operation responses from VFC
- * @param vfcResponse the VFC response
- * @return The result of the response handling
- */
- private PolicyResult onResponse(VFCResponse vfcResponse) {
- if (vfcResponse.getResponseDescriptor().getStatus().equalsIgnoreCase("finished")) {
- //
- // Consider it as success
- //
- this.completeOperation(this.attempts, " Success", PolicyResult.SUCCESS);
- if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
- return null;
- }
- return PolicyResult.SUCCESS;
- } else {
- //
- // Consider it as failure
- //
- this.completeOperation(this.attempts, " Failed", PolicyResult.FAILURE);
- if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
- return null;
- }
- // increment operation attempts for retries
- this.attempts += 1;
- return PolicyResult.FAILURE;
- }
- }
-
- public Integer getOperationTimeout() {
- //
- // Sanity check
- //
- if (this.policy == null) {
- logger.debug("getOperationTimeout returning 0");
- return 0;
- }
- logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
- return this.policy.getTimeout();
- }
-
- public String getOperationTimeoutString(int defaultTimeout) {
- Integer to = this.getOperationTimeout();
- if (to == null || to == 0) {
- return Integer.toString(defaultTimeout) + "s";
- }
- return to.toString() + "s";
- }
-
- public PolicyResult getOperationResult() {
- return this.policyResult;
- }
-
- public String getOperationMessage() {
- if (this.currentOperation != null && this.currentOperation.clOperation != null) {
- return this.currentOperation.clOperation.toMessage();
- }
-
- if (!this.operationHistory.isEmpty()) {
- return this.operationHistory.getLast().clOperation.toMessage();
- }
- return null;
- }
-
- public String getOperationMessage(String guardResult) {
- if (this.currentOperation != null && this.currentOperation.clOperation != null) {
- return this.currentOperation.clOperation.toMessage()+ ", Guard result: " + guardResult;
- }
-
- if (!this.operationHistory.isEmpty()) {
- return this.operationHistory.getLast().clOperation.toMessage() + ", Guard result: " + guardResult;
- }
- return null;
- }
-
- public String getOperationHistory() {
- if (this.currentOperation != null && this.currentOperation.clOperation != null) {
- return this.currentOperation.clOperation.toHistory();
- }
-
- if (!this.operationHistory.isEmpty()) {
- return this.operationHistory.getLast().clOperation.toHistory();
- }
- return null;
- }
-
- public List<ControlLoopOperation> getHistory() {
- LinkedList<ControlLoopOperation> history = new LinkedList<>();
- for (Operation op : this.operationHistory) {
- history.add(new ControlLoopOperation(op.clOperation));
-
- }
- return history;
- }
-
- public void setOperationHasTimedOut() {
- //
- //
- //
- this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
- }
-
- public void setOperationHasGuardDeny() {
- //
- //
- //
- this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
- }
-
- public void setOperationHasException(String message) {
- this.completeOperation(this.attempts, message, PolicyResult.FAILURE_EXCEPTION);
- }
-
- public boolean isOperationComplete() {
- //
- // Is there currently a result?
- //
- if (this.policyResult == null) {
- //
- // either we are in process or we
- // haven't started
- //
- return false;
- }
- //
- // We have some result, check if the operation failed
- //
- if (this.policyResult.equals(PolicyResult.FAILURE)) {
- //
- // Check if there were no retries specified
- //
- if (policy.getRetry() == null || policy.getRetry() == 0) {
- //
- // The result is the failure
- //
- return true;
- }
- //
- // Check retries
- //
- if (this.isRetriesMaxedOut()) {
- //
- // No more attempts allowed, reset
- // that our actual result is failure due to retries
- //
- this.policyResult = PolicyResult.FAILURE_RETRIES;
- return true;
- } else {
- //
- // There are more attempts available to try the
- // policy recipe.
- //
- return false;
- }
- }
- //
- // Other results mean we are done
- //
- return true;
- }
-
- public boolean isOperationRunning() {
- return (this.currentOperation != null);
- }
-
- /**
- * This method verifies that the operation manager may run an operation.
- * @return True if the operation can run, false otherwise
- * @throws ControlLoopException if the operation cannot run
- */
- private void verifyOperatonCanRun() throws ControlLoopException {
- //
- // They shouldn't call us if we currently running something
- //
- if (this.currentOperation != null) {
- //
- // what do we do if we are already running an operation?
- //
- throw new ControlLoopException("current operation is not null (an operation is already running)");
- }
- //
- // Check if we have maxed out on retries
- //
- if (this.policy.getRetry() == null || this.policy.getRetry() < 1) {
- //
- // No retries are allowed, so check have we even made
- // one attempt to execute the operation?
- //
- if (this.attempts >= 1) {
- //
- // We have, let's ensure our PolicyResult is set
- //
- if (this.policyResult == null) {
- this.policyResult = PolicyResult.FAILURE_RETRIES;
- }
- //
- //
- //
- throw new ControlLoopException("current operation failed and retries are not allowed");
- }
- } else {
- //
- // Have we maxed out on retries?
- //
- if (this.attempts > this.policy.getRetry()) {
- if (this.policyResult == null) {
- this.policyResult = PolicyResult.FAILURE_RETRIES;
- }
- throw new ControlLoopException("current oepration has failed after " + this.attempts + " retries");
- }
- }
-
- return;
- }
-
- private boolean isRetriesMaxedOut() {
- if (policy.getRetry() == null || policy.getRetry() == 0) {
- //
- // There were NO retries specified, so declare
- // this as completed.
- //
- return (this.attempts > 0);
- }
- return (this.attempts > policy.getRetry());
- }
-
- private void storeOperationInDataBase(){
- // Only store in DB if enabled
- boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
- if( !guardEnabled ){
- return;
- }
-
-
- // DB Properties
- Properties props = new Properties();
- if(PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL) != null &&
- PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER) != null &&
- PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS) != null){
- props.put(Util.ECLIPSE_LINK_KEY_URL, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL));
- props.put(Util.ECLIPSE_LINK_KEY_USER, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER));
- props.put(Util.ECLIPSE_LINK_KEY_PASS, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS));
- props.put(PersistenceUnitProperties.CLASSLOADER, ControlLoopOperationManager.class.getClassLoader());
- }
-
-
- String opsHistPU = System.getProperty("OperationsHistoryPU");
- if(opsHistPU == null || !opsHistPU.equals("TestOperationsHistoryPU")){
- opsHistPU = "OperationsHistoryPU";
- }
- else{
- props.clear();
- }
- EntityManager em;
- try{
- em = Persistence.createEntityManagerFactory(opsHistPU, props).createEntityManager();
- }catch(Exception e){
- logger.error("storeOperationInDataBase threw: ", e);
- return;
- }
-
- OperationsHistoryDbEntry newEntry = new OperationsHistoryDbEntry();
-
- newEntry.setClosedLoopName(this.onset.getClosedLoopControlName());
- newEntry.setRequestId(this.onset.getRequestID().toString());
- newEntry.setActor(this.currentOperation.clOperation.getActor());
- newEntry.setOperation(this.currentOperation.clOperation.getOperation());
- newEntry.setTarget(this.targetEntity);
- newEntry.setStarttime(Timestamp.from(this.currentOperation.clOperation.getStart()));
- newEntry.setSubrequestId(this.currentOperation.clOperation.getSubRequestId());
- newEntry.setEndtime(new Timestamp(this.currentOperation.clOperation.getEnd().toEpochMilli()));
- newEntry.setMessage(this.currentOperation.clOperation.getMessage());
- newEntry.setOutcome(this.currentOperation.clOperation.getOutcome());
-
- em.getTransaction().begin();
- em.persist(newEntry);
- em.getTransaction().commit();
-
- em.close();
- }
-
- private void completeOperation(Integer attempt, String message, PolicyResult result) {
- if (attempt == null) {
- logger.debug("attempt cannot be null (i.e. subRequestID)");
- return;
- }
- if (this.currentOperation != null) {
- if (this.currentOperation.attempt == attempt.intValue()) {
- this.currentOperation.clOperation.setEnd(Instant.now());
- this.currentOperation.clOperation.setMessage(message);
- this.currentOperation.clOperation.setOutcome(result.toString());
- this.currentOperation.policyResult = result;
- //
- // Save it in history
- //
- this.operationHistory.add(this.currentOperation);
- this.storeOperationInDataBase();
- //
- // Set our last result
- //
- this.policyResult = result;
- //
- // Clear the current operation field
- //
- this.currentOperation = null;
- return;
- }
- logger.debug("not current");
- }
- for (Operation op : this.operationHistory) {
- if (op.attempt == attempt.intValue()) {
- op.clOperation.setEnd(Instant.now());
- op.clOperation.setMessage(message);
- op.clOperation.setOutcome(result.toString());
- op.policyResult = result;
- return;
- }
- }
- logger.debug("Could not find associated operation");
-
- }
+ private static final long serialVersionUID = -3773199283624595410L;
+ private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
+
+ private static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
+ private static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
+ private static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
+
+ @Override
+ public String toString() {
+ return "ControlLoopOperationManager [onset=" + (onset != null ? onset.getRequestID() : "null") + ", policy="
+ + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts + ", policyResult="
+ + policyResult + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
+ + "]";
+ }
+
+ //
+ // These properties are not changeable, but accessible
+ // for Drools Rule statements.
+ //
+ public final ControlLoopEvent onset;
+ public final transient Policy policy;
+
+ //
+ // Properties used to track the Operation
+ //
+ private int attempts = 0;
+ private transient Operation currentOperation = null;
+ private LinkedList<Operation> operationHistory = new LinkedList<>();
+ private PolicyResult policyResult = null;
+ private ControlLoopEventManager eventManager = null;
+ private String targetEntity;
+
+ public ControlLoopEventManager getEventManager() {
+ return eventManager;
+ }
+
+ public void setEventManager(ControlLoopEventManager eventManager) {
+ this.eventManager = eventManager;
+ }
+
+ public String getTargetEntity() {
+ return this.targetEntity;
+ }
+
+ //
+ // Internal class used for tracking
+ //
+ private class Operation {
+ private ControlLoopOperation clOperation = new ControlLoopOperation();
+ private PolicyResult policyResult = null;
+ private int attempt = 0;
+
+ @Override
+ public String toString() {
+ return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + clOperation
+ + "]";
+ }
+ }
+
+ private String guardApprovalStatus = "NONE";// "NONE", "PERMIT", "DENY"
+ private transient Object operationRequest;
+
+ public Object getOperationRequest() {
+ return operationRequest;
+ }
+
+ public String getGuardApprovalStatus() {
+ return guardApprovalStatus;
+ }
+
+ public void setGuardApprovalStatus(String guardApprovalStatus) {
+ this.guardApprovalStatus = guardApprovalStatus;
+ }
+
+ /**
+ * Get the target for a policy.
+ *
+ * @param policy the policy
+ * @return the target
+ * @throws ControlLoopException if an error occurs
+ * @throws AAIException if an error occurs retrieving information from A&AI
+ */
+ public String getTarget(Policy policy) throws ControlLoopException, AAIException {
+ if (policy.getTarget() == null) {
+ throw new ControlLoopException("The target is null");
+ }
+
+ if (policy.getTarget().getType() == null) {
+ throw new ControlLoopException("The target type is null");
+ }
+
+ switch (policy.getTarget().getType()) {
+ case PNF:
+ throw new ControlLoopException("PNF target is not supported");
+ case VM:
+ case VNF:
+ VirtualControlLoopEvent virtualOnset = (VirtualControlLoopEvent) this.onset;
+ if (this.onset.getTarget().equalsIgnoreCase(VSERVER_VSERVER_NAME)) {
+ return virtualOnset.getAAI().get(VSERVER_VSERVER_NAME);
+ } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_ID)) {
+ return virtualOnset.getAAI().get(GENERIC_VNF_VNF_ID);
+ } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_NAME)) {
+ /*
+ * If the onset is enriched with the vnf-id, we don't need an A&AI response
+ */
+ if (virtualOnset.getAAI().containsKey(GENERIC_VNF_VNF_ID)) {
+ return virtualOnset.getAAI().get(GENERIC_VNF_VNF_ID);
+ }
+
+ /*
+ * If the vnf-name was retrieved from the onset then the vnf-id must be obtained
+ * from the event manager's A&AI GET query
+ */
+ String vnfId = this.eventManager.getVnfResponse().getVnfID();
+ if (vnfId == null) {
+ throw new AAIException("No vnf-id found");
+ }
+ return vnfId;
+ }
+ throw new ControlLoopException("Target does not match target type");
+ default:
+ throw new ControlLoopException("The target type is not supported");
+ }
+ }
+
+ /**
+ * Construct an instance.
+ *
+ * @param onset the onset event
+ * @param policy the policy
+ * @param em the event manager
+ * @throws ControlLoopException if an error occurs
+ * @throws AAIException if an error occurs retrieving information from A&AI
+ */
+ public ControlLoopOperationManager(ControlLoopEvent onset, Policy policy, ControlLoopEventManager em)
+ throws ControlLoopException, AAIException {
+ this.onset = onset;
+ this.policy = policy;
+ this.guardApprovalStatus = "NONE";
+ this.eventManager = em;
+ this.targetEntity = getTarget(policy);
+
+ //
+ // Let's make a sanity check
+ //
+ switch (policy.getActor()) {
+ case "APPC":
+ if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
+ /*
+ * The target vnf-id may not be the same as the source vnf-id specified in the
+ * yaml, the target vnf-id is retrieved by a named query to A&AI.
+ */
+ String targetVnf = AppcLcmActorServiceProvider.vnfNamedQuery(policy.getTarget().getResourceID(),
+ this.targetEntity);
+ this.targetEntity = targetVnf;
+ }
+ break;
+ case "SO":
+ break;
+ case "VFC":
+ break;
+ default:
+ throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor.");
+ }
+ }
+
+ /**
+ * Start an operation.
+ *
+ * @param onset the onset event
+ * @return the operation request
+ * @throws ControlLoopException if an error occurs
+ */
+ public Object startOperation(/* VirtualControlLoopEvent */ControlLoopEvent onset) throws ControlLoopException {
+ verifyOperatonCanRun();
+
+ //
+ // Setup
+ //
+ this.policyResult = null;
+ Operation operation = new Operation();
+ operation.attempt = ++this.attempts;
+ operation.clOperation.setActor(this.policy.getActor());
+ operation.clOperation.setOperation(this.policy.getRecipe());
+ operation.clOperation.setTarget(this.policy.getTarget().toString());
+ operation.clOperation.setSubRequestId(Integer.toString(operation.attempt));
+ //
+ // Now determine which actor we need to construct a request for
+ //
+ switch (policy.getActor()) {
+ case "APPC":
+ /*
+ * If the recipe is ModifyConfig, a legacy APPC request is constructed. Otherwise an
+ * LCMRequest is constructed.
+ */
+ this.currentOperation = operation;
+ if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
+ this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
+ operation.clOperation, this.policy, this.targetEntity);
+ } else {
+ this.operationRequest = AppcLcmActorServiceProvider.constructRequest(
+ (VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.targetEntity);
+ }
+ //
+ // Save the operation
+ //
+
+ return operationRequest;
+ case "SO":
+ SOActorServiceProvider soActorSp = new SOActorServiceProvider();
+ this.operationRequest =
+ soActorSp.constructRequest((VirtualControlLoopEvent) onset, operation.clOperation, this.policy);
+
+ // Save the operation
+ this.currentOperation = operation;
+
+ if (this.operationRequest == null) {
+ this.policyResult = PolicyResult.FAILURE;
+ }
+
+ return operationRequest;
+ case "VFC":
+ this.operationRequest = VFCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
+ operation.clOperation, this.policy, this.eventManager.getVnfResponse());
+ this.currentOperation = operation;
+ if (this.operationRequest == null) {
+ this.policyResult = PolicyResult.FAILURE;
+ }
+ return operationRequest;
+ default:
+ throw new ControlLoopException("invalid actor " + policy.getActor() + " on policy");
+ }
+ }
+
+ /**
+ * Handle a response.
+ *
+ * @param response the response
+ * @return a PolicyResult
+ */
+ public PolicyResult onResponse(Object response) {
+ //
+ // Which response is it?
+ //
+ if (response instanceof Response) {
+ //
+ // Cast APPC response and handle it
+ //
+ return onResponse((Response) response);
+ } else if (response instanceof LCMResponseWrapper) {
+ //
+ // Cast LCM response and handle it
+ //
+ return onResponse((LCMResponseWrapper) response);
+ } else if (response instanceof SOResponseWrapper) {
+ //
+ // Cast SO response and handle it
+ //
+ return onResponse((SOResponseWrapper) response);
+ } else if (response instanceof VFCResponse) {
+ //
+ // Cast VFC response and handle it
+ //
+ return onResponse((VFCResponse) response);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * This method handles operation responses from APPC.
+ *
+ * @param appcResponse the APPC response
+ * @return The result of the response handling
+ */
+ private PolicyResult onResponse(Response appcResponse) {
+ //
+ // Determine which subrequestID (ie. attempt)
+ //
+ Integer operationAttempt = null;
+ try {
+ operationAttempt = Integer.parseInt(appcResponse.getCommonHeader().getSubRequestID());
+ } catch (NumberFormatException e) {
+ //
+ // We cannot tell what happened if this doesn't exist
+ //
+ this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
+ PolicyResult.FAILURE_EXCEPTION);
+ return PolicyResult.FAILURE_EXCEPTION;
+ }
+ //
+ // Sanity check the response message
+ //
+ if (appcResponse.getStatus() == null) {
+ //
+ // We cannot tell what happened if this doesn't exist
+ //
+ this.completeOperation(operationAttempt,
+ "Policy was unable to parse APP-C response status field (it was null).",
+ PolicyResult.FAILURE_EXCEPTION);
+ return PolicyResult.FAILURE_EXCEPTION;
+ }
+ //
+ // Get the Response Code
+ //
+ ResponseCode code = ResponseCode.toResponseCode(appcResponse.getStatus().getCode());
+ if (code == null) {
+ //
+ // We are unaware of this code
+ //
+ this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.",
+ PolicyResult.FAILURE_EXCEPTION);
+ return PolicyResult.FAILURE_EXCEPTION;
+ }
+ //
+ // Ok, let's figure out what APP-C's response is
+ //
+ switch (code) {
+ case ACCEPT:
+ //
+ // This is good, they got our original message and
+ // acknowledged it.
+ //
+ // Is there any need to track this?
+ //
+ return null;
+ case ERROR:
+ case REJECT:
+ //
+ // We'll consider these two codes as exceptions
+ //
+ this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
+ PolicyResult.FAILURE_EXCEPTION);
+ if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
+ return null;
+ }
+ return PolicyResult.FAILURE_EXCEPTION;
+ case SUCCESS:
+ //
+ //
+ //
+ this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
+ PolicyResult.SUCCESS);
+ if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
+ return null;
+ }
+ return PolicyResult.SUCCESS;
+ case FAILURE:
+ //
+ //
+ //
+ this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
+ PolicyResult.FAILURE);
+ if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
+ return null;
+ }
+ return PolicyResult.FAILURE;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * This method handles operation responses from LCM.
+ *
+ * @param dmaapResponse the LCM response
+ * @return The result of the response handling
+ */
+ private PolicyResult onResponse(LCMResponseWrapper dmaapResponse) {
+ /*
+ * Parse out the operation attempt using the subrequestid
+ */
+ Integer operationAttempt = AppcLcmActorServiceProvider
+ .parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
+ if (operationAttempt == null) {
+ this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
+ PolicyResult.FAILURE_EXCEPTION);
+ }
+
+ /*
+ * Process the APPCLCM response to see what PolicyResult should be returned
+ */
+ AbstractMap.SimpleEntry<PolicyResult, String> result =
+ AppcLcmActorServiceProvider.processResponse(dmaapResponse);
+
+ if (result.getKey() != null) {
+ this.completeOperation(operationAttempt, result.getValue(), result.getKey());
+ if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
+ return null;
+ }
+ return result.getKey();
+ }
+ return null;
+ }
+
+ /**
+ * This method handles operation responses from SO.
+ *
+ * @param msoResponse the SO response
+ * @return The result of the response handling
+ */
+ private PolicyResult onResponse(SOResponseWrapper msoResponse) {
+ switch (msoResponse.getSoResponse().getHttpResponseCode()) {
+ case 200:
+ case 202:
+ //
+ // Consider it as success
+ //
+ this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + " Success",
+ PolicyResult.SUCCESS);
+ if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
+ return null;
+ }
+ return PolicyResult.SUCCESS;
+ default:
+ //
+ // Consider it as failure
+ //
+ this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + " Failed",
+ PolicyResult.FAILURE);
+ if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
+ return null;
+ }
+ return PolicyResult.FAILURE;
+ }
+ }
+
+ /**
+ * This method handles operation responses from VFC.
+ *
+ * @param vfcResponse the VFC response
+ * @return The result of the response handling
+ */
+ private PolicyResult onResponse(VFCResponse vfcResponse) {
+ if (vfcResponse.getResponseDescriptor().getStatus().equalsIgnoreCase("finished")) {
+ //
+ // Consider it as success
+ //
+ this.completeOperation(this.attempts, " Success", PolicyResult.SUCCESS);
+ if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
+ return null;
+ }
+ return PolicyResult.SUCCESS;
+ } else {
+ //
+ // Consider it as failure
+ //
+ this.completeOperation(this.attempts, " Failed", PolicyResult.FAILURE);
+ if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
+ return null;
+ }
+ // increment operation attempts for retries
+ this.attempts += 1;
+ return PolicyResult.FAILURE;
+ }
+ }
+
+ /**
+ * Get the operation timeout.
+ *
+ * @return the timeout
+ */
+ public Integer getOperationTimeout() {
+ //
+ // Sanity check
+ //
+ if (this.policy == null) {
+ logger.debug("getOperationTimeout returning 0");
+ return 0;
+ }
+ logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
+ return this.policy.getTimeout();
+ }
+
+ /**
+ * Get the operation timeout as a String.
+ *
+ * @param defaultTimeout the default timeout
+ * @return the timeout as a String
+ */
+ public String getOperationTimeoutString(int defaultTimeout) {
+ Integer to = this.getOperationTimeout();
+ if (to == null || to == 0) {
+ return Integer.toString(defaultTimeout) + "s";
+ }
+ return to.toString() + "s";
+ }
+
+ public PolicyResult getOperationResult() {
+ return this.policyResult;
+ }
+
+ /**
+ * Get the operation as a message.
+ *
+ * @return the operation as a message
+ */
+ public String getOperationMessage() {
+ if (this.currentOperation != null && this.currentOperation.clOperation != null) {
+ return this.currentOperation.clOperation.toMessage();
+ }
+
+ if (!this.operationHistory.isEmpty()) {
+ return this.operationHistory.getLast().clOperation.toMessage();
+ }
+ return null;
+ }
+
+ /**
+ * Get the operation as a message including the guard result.
+ *
+ * @param guardResult the guard result
+ * @return the operation as a message including the guard result
+ */
+ public String getOperationMessage(String guardResult) {
+ if (this.currentOperation != null && this.currentOperation.clOperation != null) {
+ return this.currentOperation.clOperation.toMessage() + ", Guard result: " + guardResult;
+ }
+
+ if (!this.operationHistory.isEmpty()) {
+ return this.operationHistory.getLast().clOperation.toMessage() + ", Guard result: " + guardResult;
+ }
+ return null;
+ }
+
+ /**
+ * Get the operation history.
+ *
+ * @return the operation history
+ */
+ public String getOperationHistory() {
+ if (this.currentOperation != null && this.currentOperation.clOperation != null) {
+ return this.currentOperation.clOperation.toHistory();
+ }
+
+ if (!this.operationHistory.isEmpty()) {
+ return this.operationHistory.getLast().clOperation.toHistory();
+ }
+ return null;
+ }
+
+ /**
+ * Get the history.
+ *
+ * @return the list of control loop operations
+ */
+ public List<ControlLoopOperation> getHistory() {
+ LinkedList<ControlLoopOperation> history = new LinkedList<>();
+ for (Operation op : this.operationHistory) {
+ history.add(new ControlLoopOperation(op.clOperation));
+
+ }
+ return history;
+ }
+
+ /**
+ * Set the operation has timed out.
+ */
+ public void setOperationHasTimedOut() {
+ //
+ //
+ //
+ this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
+ }
+
+ /**
+ * Set the operation has been denied by guard.
+ */
+ public void setOperationHasGuardDeny() {
+ //
+ //
+ //
+ this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
+ }
+
+ public void setOperationHasException(String message) {
+ this.completeOperation(this.attempts, message, PolicyResult.FAILURE_EXCEPTION);
+ }
+
+ /**
+ * Is the operation complete.
+ *
+ * @return <code>true</code> if the operation is complete, <code>false</code> otherwise
+ */
+ public boolean isOperationComplete() {
+ //
+ // Is there currently a result?
+ //
+ if (this.policyResult == null) {
+ //
+ // either we are in process or we
+ // haven't started
+ //
+ return false;
+ }
+ //
+ // We have some result, check if the operation failed
+ //
+ if (this.policyResult.equals(PolicyResult.FAILURE)) {
+ //
+ // Check if there were no retries specified
+ //
+ if (policy.getRetry() == null || policy.getRetry() == 0) {
+ //
+ // The result is the failure
+ //
+ return true;
+ }
+ //
+ // Check retries
+ //
+ if (this.isRetriesMaxedOut()) {
+ //
+ // No more attempts allowed, reset
+ // that our actual result is failure due to retries
+ //
+ this.policyResult = PolicyResult.FAILURE_RETRIES;
+ return true;
+ } else {
+ //
+ // There are more attempts available to try the
+ // policy recipe.
+ //
+ return false;
+ }
+ }
+ //
+ // Other results mean we are done
+ //
+ return true;
+ }
+
+ public boolean isOperationRunning() {
+ return (this.currentOperation != null);
+ }
+
+ /**
+ * This method verifies that the operation manager may run an operation.
+ *
+ * @return True if the operation can run, false otherwise
+ * @throws ControlLoopException if the operation cannot run
+ */
+ private void verifyOperatonCanRun() throws ControlLoopException {
+ //
+ // They shouldn't call us if we currently running something
+ //
+ if (this.currentOperation != null) {
+ //
+ // what do we do if we are already running an operation?
+ //
+ throw new ControlLoopException("current operation is not null (an operation is already running)");
+ }
+ //
+ // Check if we have maxed out on retries
+ //
+ if (this.policy.getRetry() == null || this.policy.getRetry() < 1) {
+ //
+ // No retries are allowed, so check have we even made
+ // one attempt to execute the operation?
+ //
+ if (this.attempts >= 1) {
+ //
+ // We have, let's ensure our PolicyResult is set
+ //
+ if (this.policyResult == null) {
+ this.policyResult = PolicyResult.FAILURE_RETRIES;
+ }
+ //
+ //
+ //
+ throw new ControlLoopException("current operation failed and retries are not allowed");
+ }
+ } else {
+ //
+ // Have we maxed out on retries?
+ //
+ if (this.attempts > this.policy.getRetry()) {
+ if (this.policyResult == null) {
+ this.policyResult = PolicyResult.FAILURE_RETRIES;
+ }
+ throw new ControlLoopException("current oepration has failed after " + this.attempts + " retries");
+ }
+ }
+
+ return;
+ }
+
+ private boolean isRetriesMaxedOut() {
+ if (policy.getRetry() == null || policy.getRetry() == 0) {
+ //
+ // There were NO retries specified, so declare
+ // this as completed.
+ //
+ return (this.attempts > 0);
+ }
+ return (this.attempts > policy.getRetry());
+ }
+
+ private void storeOperationInDataBase() {
+ // Only store in DB if enabled
+ boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
+ if (!guardEnabled) {
+ return;
+ }
+
+
+ // DB Properties
+ Properties props = new Properties();
+ if (PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL) != null
+ && PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER) != null
+ && PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS) != null) {
+ props.put(Util.ECLIPSE_LINK_KEY_URL, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL));
+ props.put(Util.ECLIPSE_LINK_KEY_USER, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER));
+ props.put(Util.ECLIPSE_LINK_KEY_PASS, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS));
+ props.put(PersistenceUnitProperties.CLASSLOADER, ControlLoopOperationManager.class.getClassLoader());
+ }
+
+
+ String opsHistPu = System.getProperty("OperationsHistoryPU");
+ if (opsHistPu == null || !opsHistPu.equals("TestOperationsHistoryPU")) {
+ opsHistPu = "OperationsHistoryPU";
+ } else {
+ props.clear();
+ }
+ EntityManager em;
+ try {
+ em = Persistence.createEntityManagerFactory(opsHistPu, props).createEntityManager();
+ } catch (Exception e) {
+ logger.error("storeOperationInDataBase threw: ", e);
+ return;
+ }
+
+ OperationsHistoryDbEntry newEntry = new OperationsHistoryDbEntry();
+
+ newEntry.setClosedLoopName(this.onset.getClosedLoopControlName());
+ newEntry.setRequestId(this.onset.getRequestID().toString());
+ newEntry.setActor(this.currentOperation.clOperation.getActor());
+ newEntry.setOperation(this.currentOperation.clOperation.getOperation());
+ newEntry.setTarget(this.targetEntity);
+ newEntry.setStarttime(Timestamp.from(this.currentOperation.clOperation.getStart()));
+ newEntry.setSubrequestId(this.currentOperation.clOperation.getSubRequestId());
+ newEntry.setEndtime(new Timestamp(this.currentOperation.clOperation.getEnd().toEpochMilli()));
+ newEntry.setMessage(this.currentOperation.clOperation.getMessage());
+ newEntry.setOutcome(this.currentOperation.clOperation.getOutcome());
+
+ em.getTransaction().begin();
+ em.persist(newEntry);
+ em.getTransaction().commit();
+
+ em.close();
+ }
+
+ private void completeOperation(Integer attempt, String message, PolicyResult result) {
+ if (attempt == null) {
+ logger.debug("attempt cannot be null (i.e. subRequestID)");
+ return;
+ }
+ if (this.currentOperation != null) {
+ if (this.currentOperation.attempt == attempt.intValue()) {
+ this.currentOperation.clOperation.setEnd(Instant.now());
+ this.currentOperation.clOperation.setMessage(message);
+ this.currentOperation.clOperation.setOutcome(result.toString());
+ this.currentOperation.policyResult = result;
+ //
+ // Save it in history
+ //
+ this.operationHistory.add(this.currentOperation);
+ this.storeOperationInDataBase();
+ //
+ // Set our last result
+ //
+ this.policyResult = result;
+ //
+ // Clear the current operation field
+ //
+ this.currentOperation = null;
+ return;
+ }
+ logger.debug("not current");
+ }
+ for (Operation op : this.operationHistory) {
+ if (op.attempt == attempt.intValue()) {
+ op.clOperation.setEnd(Instant.now());
+ op.clOperation.setMessage(message);
+ op.clOperation.setOutcome(result.toString());
+ op.policyResult = result;
+ return;
+ }
+ }
+ logger.debug("Could not find associated operation");
+
+ }
}