blob: 3273dc6c97b7a72dd38be896898182626ddf95b3 [file] [log] [blame]
/*-
* ============LICENSE_START=======================================================
* ONAP
* ================================================================================
* Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============LICENSE_END=========================================================
*/
package org.onap.policy.controlloop;
import org.onap.policy.controlloop.VirtualControlLoopEvent;
import org.onap.policy.controlloop.VirtualControlLoopNotification;
import org.onap.policy.controlloop.ControlLoopEventStatus;
import org.onap.policy.controlloop.ControlLoopNotificationType;
import org.onap.policy.controlloop.ControlLoopLogger;
import org.onap.policy.controlloop.policy.PolicyResult;
import org.onap.policy.controlloop.policy.ControlLoopPolicy;
import org.onap.policy.controlloop.policy.Policy;
import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NEW_EVENT_STATUS;
import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
import org.onap.policy.controlloop.actor.so.SOActorServiceProvider;
import org.onap.policy.appc.Request;
import org.onap.policy.appc.Response;
import org.onap.policy.appc.CommonHeader;
import org.onap.policy.appclcm.LCMRequestWrapper;
import org.onap.policy.appclcm.LCMResponseWrapper;
import org.onap.policy.appclcm.LCMRequest;
import org.onap.policy.appclcm.LCMResponse;
import org.onap.policy.appclcm.LCMCommonHeader;
import org.onap.policy.vfc.VFCRequest;
import org.onap.policy.vfc.VFCResponse;
import org.onap.policy.vfc.VFCManager;
import org.onap.policy.so.SOManager;
import org.onap.policy.so.SORequest;
import org.onap.policy.so.SORequestStatus;
import org.onap.policy.so.SORequestDetails;
import org.onap.policy.so.SOModelInfo;
import org.onap.policy.so.SOCloudConfiguration;
import org.onap.policy.so.SORequestInfo;
import org.onap.policy.so.SORequestParameters;
import org.onap.policy.so.SORelatedInstanceListElement;
import org.onap.policy.so.SORelatedInstance;
import org.onap.policy.so.SOResponse;
import org.onap.policy.guard.PolicyGuard;
import org.onap.policy.guard.PolicyGuard.LockResult;
import org.onap.policy.guard.TargetLock;
import org.onap.policy.guard.GuardResult;
import org.onap.policy.guard.PolicyGuardRequest;
import org.onap.policy.guard.PolicyGuardResponse;
import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
import org.onap.policy.guard.PolicyGuardXacmlHelper;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import java.time.Instant;
import java.util.LinkedList;
import java.util.Iterator;
import org.onap.policy.drools.system.PolicyEngine;
declare Params
closedLoopControlName : String
controlLoopYaml : String
end
declare OperationTimer
closedLoopControlName : String
requestID : String
delay : String
end
declare ControlLoopTimer
closedLoopControlName : String
requestID : String
delay : String
end
/*
*
* Called once and only once to insert the parameters into working memory for this Closed Loop policy.
*
*/
rule "${policyName}.SETUP"
when
then
Params params = new Params();
params.setClosedLoopControlName("${closedLoopControlName}");
params.setControlLoopYaml("${controlLoopYaml}");
insert(params);
// Note: globals have bad behavior when persistence is used,
// hence explicitly getting the logger vs using a global
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(), params.getControlLoopYaml());
String sqlDbUsername = PolicyEngine.manager.getEnvironmentProperty("sql.db.username");
String aaiUrl = PolicyEngine.manager.getEnvironmentProperty("aai.url");
String aaiUsername = PolicyEngine.manager.getEnvironmentProperty("aai.username");
String aaiPassword = PolicyEngine.manager.getEnvironmentProperty("aai.password");
String soUrl =PolicyEngine.manager.getEnvironmentProperty("so.url");
String soUsername = PolicyEngine.manager.getEnvironmentProperty("so.username");
String soPassword = PolicyEngine.manager.getEnvironmentProperty("so.password");
String vfcUrl =PolicyEngine.manager.getEnvironmentProperty("vfc.url");
String vfcUsername = PolicyEngine.manager.getEnvironmentProperty("vfc.username");
String vfcPassword = PolicyEngine.manager.getEnvironmentProperty("vfc.password");
String guardUrl = PolicyEngine.manager.getEnvironmentProperty("guard.url");
String guardUsername = PolicyEngine.manager.getEnvironmentProperty("pdpx.username");
String guardPassword = PolicyEngine.manager.getEnvironmentProperty("pdpx.password");
String guardJdbcUrl = PolicyEngine.manager.getEnvironmentProperty("guard.jdbc.url");
String guardDisabled = PolicyEngine.manager.getEnvironmentProperty("guard.disabled");
logger.info("{}: {} : AAI=[{}:{}]", params.getClosedLoopControlName(), drools.getRule().getName(), aaiUrl, aaiUsername);
logger.info("{}: {} : SO=[{}:{}]", params.getClosedLoopControlName(), drools.getRule().getName(), soUrl, soUsername);
logger.info("{}: {} : VFC=[{}:{}]", params.getClosedLoopControlName(), drools.getRule().getName(), vfcUrl, vfcUsername);
logger.info("{}: {} : GUARD=[{}:{}:{}:{}]", params.getClosedLoopControlName(), drools.getRule().getName(), guardUrl, guardUsername, guardJdbcUrl, guardDisabled);
logger.info("{}: {} : DB=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(), sqlDbUsername);
end
/*
*
* This rule responds to DCAE Events where there is no manager yet. Either it is
* the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
*
*/
rule "${policyName}.EVENT"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
not ( ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID ) )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
try {
//
// Check the event, because we need it to not be null when
// we create the ControlLoopEventManager. The ControlLoopEventManager
// will do extra syntax checking as well check if the closed loop is disabled.
//
if ($event.requestID == null) {
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.notification = ControlLoopNotificationType.REJECTED;
notification.from = "policy";
notification.message = "Missing requestID";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
//
// Let interested parties know
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Retract it from memory
//
retract($event);
} else {
//
// Create an EventManager
//
ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(), $event.requestID);
//
// Determine if EventManager can actively process the event (i.e. syntax, is_closed_loop_disabled checks etc.)
//
VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
notification.from = "pdp-0001-controller=controlloop"; // Engine.getInstanceName()
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
//
// Are we actively pursuing this event?
//
if (notification.notification == ControlLoopNotificationType.ACTIVE) {
//
// Insert Event Manager into memory, this will now kick off processing.
//
insert(manager);
//
// Let interested parties know
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Setup the Overall Control Loop timer
//
ControlLoopTimer clTimer = new ControlLoopTimer();
clTimer.setClosedLoopControlName($event.closedLoopControlName);
clTimer.setRequestID($event.requestID.toString());
clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
//
// Insert it
//
insert(clTimer);
} else {
//
// Let interested parties know
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Retract it from memory
//
retract($event);
}
//
// Now that the manager is inserted into Drools working memory, we'll wait for
// another rule to fire in order to continue processing. This way we can also
// then screen for additional ONSET and ABATED events for this RequestID.
//
}
} catch (Exception e) {
logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.notification = ControlLoopNotificationType.REJECTED;
notification.message = "Exception occurred " + e.getMessage();
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
//
//
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Retract the event
//
retract($event);
}
end
/*
*
* This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
* is now created. We can start processing the yaml specification via the Event Manager.
*
*/
rule "${policyName}.EVENT.MANAGER"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$clTimer : ControlLoopTimer ( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}: event={} manager={} clTimer={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $clTimer);
//
// Check which event this is.
//
ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
//
// Check what kind of event this is
//
if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
//
// We don't care about subsequent onsets
//
logger.info("{}: {}: subsequent onset",
$params.getClosedLoopControlName(), drools.getRule().getName());
retract($event);
return;
}
if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
//
// Ignore any bad syntax events
//
logger.warn("{}: {}: syntax error",
$params.getClosedLoopControlName(), drools.getRule().getName());
retract($event);
return;
}
//
// We only want the initial ONSET event in memory,
// all the other events need to be retracted to support
// cleanup and avoid the other rules being fired for this event.
//
if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
logger.warn("{}: {}: no first onset",
$params.getClosedLoopControlName(), drools.getRule().getName());
retract($event);
}
logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(),
drools.getRule().getName(), $event.target);
//
// Now start seeing if we need to process this event
//
try {
//
// Check if this is a Final Event
//
VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
if (notification != null) {
//
// Its final, but are we waiting for abatement?
//
if ($manager.getNumAbatements() > 0) {
logger.info("{}: {}: abatement received for {}. Closing the control loop",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event.requestID);
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
//
// In this case, we are done
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Unlock the target
//
TargetLock lock = $manager.unlockCurrentOperation();
if (lock != null) {
logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
drools.getRule().getName(), lock);
retract(lock);
}
//
// Retract everything from memory
//
logger.info("{}: {}: retracting onset, manager, and timer",
$params.getClosedLoopControlName(), drools.getRule().getName());
retract($manager.getOnsetEvent());
retract($manager);
retract($clTimer);
//
// TODO - what if we get subsequent Events for this RequestID?
// By default, it will all start over again. May be confusing for Ruby.
// Or, we could track this and then subsequently ignore the events
//
} else {
//
// Check whether we need to wait for abatement
//
if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.notification == ControlLoopNotificationType.FINAL_SUCCESS) {
logger.info("{}: {}: waiting for abatement ..",
$params.getClosedLoopControlName(), drools.getRule().getName());
} else {
logger.info("{}: {}: no abatement expect for {}. Closing the control loop",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event.requestID);
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
//
// In this case, we are done
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Unlock the target
//
TargetLock lock = $manager.unlockCurrentOperation();
if (lock != null) {
logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
drools.getRule().getName(), lock);
retract(lock);
}
//
// Retract everything from memory
//
logger.info("{}: {}: retracting onset, manager, and timer",
$params.getClosedLoopControlName(), drools.getRule().getName());
retract($manager.getOnsetEvent());
retract($manager);
retract($clTimer);
}
}
} else {
//
// NOT final, so let's ask for the next operation
//
ControlLoopOperationManager operation = $manager.processControlLoop();
if (operation != null) {
logger.info("{}: {}: starting operation={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
operation);
//
// insert into memory
//
insert(operation);
//
// insert operation timeout object
//
OperationTimer opTimer = new OperationTimer();
opTimer.setClosedLoopControlName($event.closedLoopControlName);
opTimer.setRequestID($event.requestID.toString());
opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
insert(opTimer);
//
// Let's ask for a lock right away
//
LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
logger.info("{}: {}: guard lock acquired={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
result.getB());
//
// Insert into memory
//
insert(result.getB());
}
} else {
//
// Probably waiting for abatement
//
logger.info("{}: {}: no operation, probably waiting for abatement",
$params.getClosedLoopControlName(), drools.getRule().getName());
}
}
} catch (Exception e) {
logger.warn("{}: {}: unexpected",
$params.getClosedLoopControlName(),
drools.getRule().getName(), e);
//
// TODO should we abort if we get an exception?
//
}
end
/*
*
*
*
*/
rule "${policyName}.EVENT.MANAGER.OPERATION.NOT_LOCKED.TIMEOUT"
timer (int: 5s 5s)
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
not ( TargetLock (requestID == $event.requestID) )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}: event={} manager={} operation={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation);
//
// Need to ask for a Lock
//
LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
logger.info("{}: {}: guard lock acquired={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
result.getB());
//
// Insert into memory
//
insert(result.getB());
}
end
/*
*
* Guard Permitted, let's send request to the actor.
*
*/
rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID, "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
$lock : TargetLock (requestID == $event.requestID)
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}: event={} manager={} operation={} lock={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock);
Object request = $operation.startOperation($event);
if (request != null) {
logger.debug("{}: {}: starting operation ..",
$params.getClosedLoopControlName(), drools.getRule().getName());
//
// Tell interested parties we are performing this Operation
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.notification = ControlLoopNotificationType.OPERATION;
notification.message = $operation.getOperationMessage();
notification.history = $operation.getHistory();
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
switch ($operation.policy.getActor()){
case "APPC":
if (request instanceof Request) {
PolicyEngine.manager.deliver("APPC-CL", request);
}
else if (request instanceof LCMRequestWrapper) {
PolicyEngine.manager.deliver("APPC-LCM-READ", request);
}
break;
case "SO":
// at this point the AAI named query request should have already been made, the response recieved and used
// in the construction of the SO Request which is stored in operationRequest
if(request instanceof SORequest) {
// Call SO. The response will be inserted into memory once it's received
SOActorServiceProvider.sendRequest(drools.getWorkingMemory(), request);
}
break;
case "VFC":
if (request instanceof VFCRequest) {
// Start VFC thread
Thread t = new Thread(new VFCManager(drools.getWorkingMemory(), (VFCRequest)request));
t.start();
}
break;
}
} else {
//
// What happens if its null?
//
logger.warn("{}: {}: unexpected null operation request",
$params.getClosedLoopControlName(),
drools.getRule().getName());
}
end
/*
*
* We were able to acquire a lock so now let's ask Xacml Guard whether
* we are allowed to proceed with the request to the actor.
*
*/
rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID, getGuardApprovalStatus() == "NONE" )
$lock : TargetLock (requestID == $event.requestID)
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}: event={} manager={} operation={} lock={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock);
//
// Sending notification that we are about to query Guard ("DB write - start operation")
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.notification = ControlLoopNotificationType.OPERATION;
notification.message = "Sending guard query for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe();
notification.history = $operation.getHistory();
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
// just change guardEnabled to false.
//
// In order to use REST XACML, provide a URL instead of "" as a second argument
// to the CallGuardTask() and set the first argument to null
// (instead of XacmlPdpEngine).
//
// NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
if(guardEnabled){
Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
drools.getWorkingMemory(),
$event.closedLoopControlName,
$operation.policy.getActor().toString(),
$operation.policy.getRecipe(),
$manager.getTargetInstance($operation.policy),
//$event.target,
$event.requestID.toString()
));
t.start();
}
else{
insert(new PolicyGuardResponse("Permit", $event.requestID, $operation.policy.getRecipe()));
}
end
//
// This rule will be triggered when a thread talking to the XACML Guard inserts a
// guardResponse object into the working memory
//
rule "${policyName}.GUARD.RESPONSE"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
$lock : TargetLock (requestID == $event.requestID)
$opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
$guardResponse : PolicyGuardResponse(requestID == $event.requestID, $operation.policy.recipe == operation)
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock, $opTimer, $guardResponse);
//we will permit the operation if there was no Guard for it
if("Indeterminate".equalsIgnoreCase($guardResponse.result)){
$guardResponse.result = "Permit";
}
//
// This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.notification = ControlLoopNotificationType.OPERATION;
notification.message = "Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe() + " is " + $guardResponse.result;
notification.history = $operation.getHistory();
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
if("Permit".equalsIgnoreCase($guardResponse.result)){
modify($operation){setGuardApprovalStatus($guardResponse.result)};
}
else {
//This is the Deny case
$operation.setOperationHasGuardDeny();
retract($opTimer);
retract($operation);
modify($manager) {finishOperation($operation)};
}
retract($guardResponse);
end
/*
*
* This rule responds to APPC Response Events
*
* I would have like to be consistent and write the Response like this:
* $response : Response( CommonHeader.RequestID == $onset.requestID )
*
* However, no compile error was given. But a runtime error was given. I think
* because drools is confused between the classname CommonHeader vs the property CommonHeader.
*
*/
rule "${policyName}.APPC.RESPONSE"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
$opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
$lock : TargetLock (requestID == $event.requestID)
$response : Response( getCommonHeader().RequestID == $event.requestID )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock, $opTimer, $response);
//
// Get the result of the operation
//
PolicyResult policyResult = $operation.onResponse($response);
if (policyResult != null) {
logger.debug("{}: {}: operation finished - result={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
policyResult);
//
// This Operation has completed, construct a notification showing our results. (DB write - end operation)
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
notification.message = $operation.getOperationHistory();
notification.history = $operation.getHistory();
if (policyResult.equals(PolicyResult.SUCCESS)) {
notification.notification = ControlLoopNotificationType.OPERATION_SUCCESS;
//
// Let interested parties know
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
} else {
notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
//
// Let interested parties know
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
}
//
// Ensure the operation is complete
//
if ($operation.isOperationComplete() == true) {
//
// It is complete, remove it from memory
//
retract($operation);
//
// We must also retract the timer object
// NOTE: We could write a Rule to do this
//
retract($opTimer);
//
// Complete the operation
//
modify($manager) {finishOperation($operation)};
} else {
//
// Just doing this will kick off the LOCKED rule again
//
modify($operation) {};
}
} else {
//
// Its not finished yet (i.e. expecting more Response objects)
//
// Or possibly it is a leftover response that we timed the request out previously
//
}
//
// We are going to retract these objects from memory
//
retract($response);
end
/*
*
* The problem with Responses is that they don't have a controlLoopControlName
* field in them, so the only way to attach them is via RequestID. If we have multiple
* control loop .drl's loaded in the same container, we need to be sure the cleanup
* rules don't remove Responses for other control loops.
*
*/
rule "${policyName}.APPC.RESPONSE.CLEANUP"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$response : Response($id : getCommonHeader().RequestID )
not ( VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), requestID == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
logger.debug("{}: {}: orphan appc response={}",
$params.getClosedLoopControlName(), drools.getRule().getName(), $id);
//
// Retract it
//
retract($response);
end
/*
*
* This rule responds to APPC Response Events using the new LCM interface provided by appc
*
*/
rule "${policyName}.APPC.LCM.RESPONSE"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
$opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
$lock : TargetLock (requestID == $event.requestID)
$response : LCMResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.requestID )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock, $operation, $opTimer, $response);
//
// Get the result of the operation
//
PolicyResult policyResult = $operation.onResponse($response);
if (policyResult != null) {
logger.debug("{}: {}: operation finished - result={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
policyResult);
//
// This Operation has completed, construct a notification showing our results. (DB write - end operation)
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
notification.message = $operation.getOperationHistory();
notification.history = $operation.getHistory();
if (policyResult.equals(PolicyResult.SUCCESS)) {
notification.notification = ControlLoopNotificationType.OPERATION_SUCCESS;
} else {
notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
}
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Ensure the operation is complete
//
if ($operation.isOperationComplete() == true) {
//
// It is complete, remove it from memory
//
retract($operation);
//
// We must also retract the timer object
// NOTE: We could write a Rule to do this
//
retract($opTimer);
//
// Complete the operation
//
modify($manager) {finishOperation($operation)};
} else {
//
// Just doing this will kick off the LOCKED rule again
//
modify($operation) {};
}
} else {
//
// Its not finished yet (i.e. expecting more Response objects)
//
// Or possibly it is a leftover response that we timed the request out previously
//
}
//
// We are going to retract these objects from memory
//
retract($response);
end
/*
*
* Clean Up any lingering LCM reponses
*
*/
rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$response : LCMResponseWrapper($id : getBody().getCommonHeader().getRequestId )
not ( VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), requestID == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
logger.debug("{}: {}: orphan appc response={}",
$params.getClosedLoopControlName(), drools.getRule().getName(), $id);
//
// Retract it
//
retract($response);
end
/*
*
* This rule responds to SO Response Events
*
*/
rule "${policyName}.SO.RESPONSE"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
$opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
$lock : TargetLock (requestID == $event.requestID)
$response : SOResponse( requestReferences.requestId.toString() == $event.requestID.toString() )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock, $operation, $opTimer, $response);
// Get the result of the operation
//
PolicyResult policyResult = $operation.onResponse($response);
if (policyResult != null) {
logger.debug("{}: {}: operation finished - result={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
policyResult);
//
// This Operation has completed, construct a notification showing our results
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
notification.message = $operation.getOperationHistory();
notification.history = $operation.getHistory();
if (policyResult.equals(PolicyResult.SUCCESS)) {
notification.notification = ControlLoopNotificationType.OPERATION_SUCCESS;
} else {
notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
}
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Ensure the operation is complete
//
if ($operation.isOperationComplete() == true) {
//
// It is complete, remove it from memory
//
retract($operation);
//
// We must also retract the timer object
// NOTE: We could write a Rule to do this
//
retract($opTimer);
//
// Complete the operation
//
modify($manager) {finishOperation($operation)};
} else {
//
// Just doing this will kick off the LOCKED rule again
//
modify($operation) {};
}
} else {
//
// Its not finished yet (i.e. expecting more Response objects)
//
// Or possibly it is a leftover response that we timed the request out previously
//
}
//
// We are going to retract these objects from memory
//
retract($response);
end
/*
*
* This rule responds to VFC Response Events
*
*/
rule "${policyName}.VFC.RESPONSE"
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
$opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() )
$lock : TargetLock (requestID == $event.requestID)
$response : VFCResponse( requestId.toString() == $event.requestID.toString() )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock, $operation, $opTimer, $response);
// Get the result of the operation
//
PolicyResult policyResult = $operation.onResponse($response);
if (policyResult != null) {
//
// This Operation has completed, construct a notification showing our results
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
notification.message = $operation.getOperationHistory();
notification.history = $operation.getHistory();
//
// Ensure the operation is complete
//
if ($operation.isOperationComplete() == true) {
//
// It is complete, remove it from memory
//
retract($operation);
//
// We must also retract the timer object
// NOTE: We could write a Rule to do this
//
retract($opTimer);
//
// Complete the operation
//
modify($manager) {finishOperation($operation)};
} else {
//
// Just doing this will kick off the LOCKED rule again
//
modify($operation) {};
}
} else {
//
// Its not finished yet (i.e. expecting more Response objects)
//
// Or possibly it is a leftover response that we timed the request out previously
//
}
//
// We are going to retract these objects from memory
//
retract($response);
end
/*
*
* This is the timer that manages the timeout for an individual operation.
*
*/
rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
timer (expr: $to )
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID )
$opTimer : OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString(), $to : getDelay() )
$lock : TargetLock (requestID == $event.requestID)
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $operation, $lock, $operation, $opTimer);
//
// Tell it its timed out
//
$operation.setOperationHasTimedOut();
//
// Create a notification for it ("DB Write - end operation")
//
VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
notification.notification = ControlLoopNotificationType.OPERATION_FAILURE;
notification.message = $operation.getOperationHistory();
notification.history = $operation.getHistory();
//
// Let interested parties know
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
//
// Get rid of the timer
//
retract($opTimer);
//
// Ensure the operation is complete
//
if ($operation.isOperationComplete() == true) {
//
// It is complete, remove it from memory
//
retract($operation);
//
// Complete the operation
//
modify($manager) {finishOperation($operation)};
} else {
//
// Just doing this will kick off the LOCKED rule again
//
modify($operation) {};
}
end
/*
*
* This is the timer that manages the overall control loop timeout.
*
*/
rule "${policyName}.EVENT.MANAGER.TIMEOUT"
timer (expr: $to )
when
$params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
$event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
$manager : ControlLoopEventManager( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID )
$clTimer : ControlLoopTimer ( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString(), $to : getDelay() )
$operations : LinkedList()
from collect( ControlLoopOperationManager( onset.closedLoopControlName == $event.closedLoopControlName, onset.requestID == $event.requestID ) )
$opTimers : LinkedList()
from collect( OperationTimer( closedLoopControlName == $event.closedLoopControlName, requestID == $event.requestID.toString() ) )
$locks : LinkedList()
from collect( TargetLock (requestID == $event.requestID) )
then
Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
if ($operations == null) {
logger.debug("{}: {}: event={} manager={} clTimer={} operations=0",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $clTimer);
} else {
logger.debug("{}: {}: event={} manager={} clTimer={} operations={}",
$params.getClosedLoopControlName(), drools.getRule().getName(),
$event, $manager, $clTimer, $operations.size());
}
//
// Tell the Event Manager it has timed out
//
VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
if (notification != null) {
notification.from = "policy";
notification.policyName = drools.getRule().getName();
notification.policyScope = "${policyScope}";
notification.policyVersion = "${policyVersion}";
//
// Let interested parties know
//
PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
}
//
// Retract EVERYTHING
//
retract($event);
retract($manager);
retract($clTimer);
if ($operations != null && $operations.size() > 0) {
Iterator<ControlLoopOperationManager> iter = $operations.iterator();
while (iter.hasNext()) {
ControlLoopOperationManager manager = iter.next();
retract(manager);
}
}
if ($opTimers != null && $opTimers.size() > 0) {
Iterator<OperationTimer> iter = $opTimers.iterator();
while (iter.hasNext()) {
OperationTimer opTimer = iter.next();
retract(opTimer);
}
}
if ($locks != null && $locks.size() > 0) {
Iterator<TargetLock> iter = $locks.iterator();
while (iter.hasNext()) {
TargetLock lock = iter.next();
//
// Ensure we release the lock
//
PolicyGuard.unlockTarget(lock);
//
//
//
retract(lock);
}
}
end