...
}
}
Establish
...
Persistent Connection
Functionality
Collector establishes long term connectivity persistent connection with SOTN Controller and the controller will continuously Push the subscribed notification over.
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
version: '2.1'
services:
restconfcollector:
image: "restconfcollector"
container_name: "restconf_collector"
restart: "always"
hostname: "restconf-collector"
labels:
- "SERVICE_NAME=restconf_collector"
|
Blueprint for Holmes Rule Manager
...
CCVPN Close Loop requires Holmes to correlate route down alarms from SOTN Controllers from different sites. (Refer to this page on Holmes installation,)
In Phase 1, for the minimum, two of the above defined Route_Down_Alarm will be correlated within time window of 15 - 30, for instance, milliseconds. (Refer to this page as examples.)
Rule Creation
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{ "ruleName": "CCVPN", "loopControlNamecontent": "ControlLoop-CCVPN-2179b738-fd36-4843-a71a-a8c24c70c55b", "description": "This rule is designed for the correlation analysis for the CCVPN use case.", "content": "package "package org.onap.holmes.ccvpn;\n\ndialect \"java\"\n\nimport org.onap.holmes.droolsRule;\ncommon.api.stat.VesAlarm;\nimport org.onap.holmes.common.api.dmaapstat.DmaapServiceAlarmAdditionalField;\nimport org.onap.holmes.common.apiaai.stat.VesAlarmAaiQuery4Ccvpn;\nimport org.onap.holmes.common.aaiexception.CorrelationUtilCorrelationException;\nimport org.onap.holmes.common.dmaap.entity.PolicyMsg;\nimport org.onap.holmes.common.dropwizard.ioc.dmaap.DmaapService;\nimport org.onap.holmes.common.utils.ServiceLocatorHolderDroolsLog;\nimport org.onap.holmes.common.dropwizard.ioc.utils.DroolsLogServiceLocatorHolder;\n\nimport \n\nrule \"Relation_analysis_Rule\"\nsalience 200\nno-loop true\n when\n $root : VesAlarm(alarmIsCleared == 0,\n $sourceId: sourceId, sourceId != null && !sourceId.equals(\"\"),\n\t\t\t$sourceName: sourceName, sourceName != null && !sourceName.equals(\"\"),\n\t\t\t$startEpochMicrosec: startEpochMicrosec,\n specificProblem in (\"Fault_SOTN_Service_Failure\"),\n $eventId: eventId)\n $child : VesAlarm( eventId != $eventId, parentId == null,\n specificProblem in (\"Fault_SOTN_Service_Failure\"),\n startEpochMicrosec < $startEpochMicrosec + 60000 && startEpochMicrosec > $startEpochMicrosec - 60000 )\n then\n\t\t$child.setParentId($root.getEventId());\n\t\tupdate($child);\n\t\t\nend\n\nrule \"root_has_child_handle_Rule\"\nsalience 150\nno-loop true\n\twhen\n\t\t$root : VesAlarm(alarmIsCleared == 0, rootFlag == 0, $eventId: eventId)\n\t\t$child : VesAlarm(eventId != $eventId, parentId == $eventId)\n\tthen\n\t\tDmaapService dmaapService = ServiceLocatorHolder.getLocator().getService(DmaapService.class);\n\t\tPolicyMsg policyMsg = dmaapService.getPolicyMsg($root, $child, \"org.onap.holmes.droolsRule\");\n dmaapService.publishPolicyMsg(policyMsg, \"unauthenticated.DCAE_CL_OUTPUT\");\n\t\t$root.setRootFlag(1);\n\t\tupdate($root);\nend\n\nrule \"root_no_child_handle_Rule\"\nsalience 100\nno-loop true\n when\n $root : VesAlarm(alarmIsCleared == 0, rootFlag == 0,\n sourceId != null && !sourceId.equals(\"\"),\n\t\t\tsourceName != null && !sourceName.equals(\"\"),\n specificProblem in (\"Fault_SOTN_Service_Failure\"))\n then\n\t\tDmaapService dmaapService = ServiceLocatorHolder.getLocator().getService(DmaapService.class);\n\t\tPolicyMsg policyMsg = dmaapService.getPolicyMsg($root, null, \"org.onap.holmes.droolsRule\");\n dmaapService.publishPolicyMsg(policyMsg, \"unauthenticated.DCAE_CL_OUTPUT\");\n\t\t$root.setRootFlag(1);\n\t\tupdate($root);\nend\n\nrule \"root_cleared_handle_Rule\"\nsalience 100\nno-loop true\n when\n $root : VesAlarm(alarmIsCleared == 1, rootFlag == 1)\n then\n\t\tDmaapService dmaapService = ServiceLocatorHolder.getLocator().getService(DmaapService.class);\n\t\tPolicyMsg policyMsg = dmaapService.getPolicyMsg($root, null, \"org.onap.holmes.droolsRule\");\n dmaapService.publishPolicyMsg(policyMsg, \"unauthenticated.DCAE_CL_OUTPUT\");\n\t\tretract($root);\nend\n\nrule \"child_handle_Rule\"\nsalience 100\nno-loop true\n when\n $child : VesAlarm(alarmIsCleared == 1, rootFlag == 0)\n then\n\t\tretract($child);\nend", "enabled": 1 } |
To illustrate, the content field in the above rule is presented as readable format in the following. We need to convert it to valid json string when uploading to Holmes.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
package org.onap.holmes.ccvpn;
dialect "java"
import org.onap.holmes.common.api.stat.VesAlarm;
import org.onap.holmes.common.api.stat.AlarmAdditionalField;
import org.onap.holmes.common.aai.AaiQuery4Ccvpn;
import org.onap.holmes.common.exception.CorrelationException;
import org.onap.holmes.common.dmaap.entity.PolicyMsg;
import org.onap.holmes.common.dmaap.DmaapService;
import org.onap.holmes.common.utils.DroolsLog;
import org.onap.holmes.common.dropwizard.ioc.utils.ServiceLocatorHolder;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
function String getAdditionalField(VesAlarm a, String field) {
List<AlarmAdditionalField> fields = a.getAlarmAdditionalInformation();
for (AlarmAdditionalField f : fields) {
if (f.getName().equals(field)) {
return f.getValue();
}
}
return null;
}
function String getLogicLink(VesAlarm alarm) {
AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();
return aai.getLogicLink(
getAdditionalField(alarm, "networkId"),
getAdditionalField(alarm, "node"),
getAdditionalField(alarm, "tp-id"),
getAdditionalField(alarm, "oper-status")
);
}
function boolean isCorrelated(VesAlarm a, VesAlarm b) {
String logicLinkA = getLogicLink(a);
if (logicLinkA == null) {
return false;
}
String logicLinkB = getLogicLink(b);
if (logicLinkB == null) {
return false;
}
return logicLinkA.equals(logicLinkB);
}
function void updateAaiStatus(String networkId, String pnfName, String ifName,
String linkName, String status) {
AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();
Map<String, Object> body = new HashMap<String, Object>(){
{
put("operational-status", status);
}
};
aai.updateLogicLinkStatus(linkName, body);
aai.updateTerminalPointStatus(networkId, pnfName, ifName, body);
}
function Map<String, Object> getAdditionalResourceInfo(String networkId, String pnfName, String ifName, String status) {
AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();
JSONArray instances = aai.getServiceInstances(networkId, pnfName, ifName, status);
Map<String, Object> ret = new HashMap<String, Object>();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < instances.size(); ++i) {
JSONObject o = instances.getJSONObject(i);
String name = o.getString("service-instance-name");
ret.put(name + ".input-parameters", o.getString("input-parameters"));
sb.append(name).append(",");
}
ret.put("service-instance.service-instance-name", sb.substring(0, sb.length() -1).toString());
ret.put("vserver.vserver-name", "TBD");
ret.put("globalSubscriberId", instances.getJSONObject(0).getString("globalSubscriberId"));
ret.put("serviceType", instances.getJSONObject(0).getString("serviceType"));
return ret;
}
function PolicyMsg createPolicyMsg(VesAlarm alarm) {
PolicyMsg m = new PolicyMsg();
m.setPolicyVersion("1.0.0.5");
m.setPolicyName("CCVPN");
m.setPolicyScope("service=SOTNService,type=SampleType,closedLoopControlName=CL-CCVPN-d925ed73-8231-4d02-9545-db4e101f88f8");
m.setClosedLoopControlName(DmaapService.loopControlNames.get("org.onap.holmes.ccvpn"));
m.setRequestID(UUID.randomUUID().toString());
m.setClosedLoopAlarmStart(alarm.getStartEpochMicrosec());
m.setClosedLoopAlarmEnd(alarm.getLastEpochMicrosec());
m.setTarget("vserver.vserver-name");
m.setAai(getAdditionalResourceInfo(
getAdditionalField(alarm, "networkId"),
getAdditionalField(alarm, "node"),
getAdditionalField(alarm, "tp-id"),
getAdditionalField(alarm, "oper-status")
));
DmaapService.alarmUniqueRequestID.put(alarm.getEventId(), m.getRequestID());
return m;
}
rule "Update AAI Information"
no-loop true
salience 300
when
$a: VesAlarm(eventName.indexOf("Fault_Route_Status") != -1)
then
updateAaiStatus (
getAdditionalField($a, "networkId"),
getAdditionalField($a, "node"),
getAdditionalField($a, "tp-id"),
getLogicLink($a),
getAdditionalField($a, "oper-status")
);
end
rule "Set Up Correlation"
no-loop true
salience 200
when
$a: VesAlarm($id: eventId,
$start: startEpochMicrosec,
eventName.indexOf("Fault_Route_Status") != -1)
$b: VesAlarm(eventId != $id,
eventName.indexOf("Fault_Route_Status") != -1,
Math.abs(startEpochMicrosec - $start) < 60000)
then
if ("down".equalsIgnoreCase(getAdditionalField($a, "oper-status"))
&& "down".equalsIgnoreCase(getAdditionalField($b, "oper-status"))) {
if (isCorrelated($a, $b)){
// If any of the alarms have been marked as root, a policy message has ever been created and sent. Do NOT send it again.
if ($a.getRootFlag() != 1 && $b.getRootFlag() != 1) {
PolicyMsg msg = createPolicyMsg($a);
DmaapService dmaapService = ServiceLocatorHolder.getLocator().getService(DmaapService.class);
dmaapService.publishPolicyMsg(msg, "unauthenticated.DCAE_CL_OUTPUT");
}
$a.setRootFlag(1);
$b.setRootFlag(1);
update($a);
update($b);
}
}
end
rule "Clear Alarms"
no-loop true
salience 100
when
$a: VesAlarm(eventName.indexOf("Fault_Route_Status") != -1)
then
if ("up".equalsIgnoreCase(getAdditionalField($a, "oper-status"))) {
if (DmaapService.alarmUniqueRequestID.containsKey($a.getEventId())) {
DmaapService.alarmUniqueRequestID.remove($a.getEventId());
}
//TODO: send alarm clearing message to Policy - for now it's not needed.
//...
retract($a);
}
end |
Rule Execution
After the correlation is done successfully, there should be a corresponding control loop event defined in the following section published on the unauthenticated.DCAE_CL_OUTPUT topic of DMaaP.
POLICY
Policy Creation
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
controlLoop:
version: 2.0.0
controlLoopName: ControlLoop-CCVPN-2179b738-fd36-4843-a71a-a8c24c70c55b
trigger_policy: unique-policy-id-16-receateE2EService
timeout: 3600
abatement: false
policies:
- id: unique-policy-id-16-recreateE2EService
name: Recreate E2E Service
description:
actor: SO
recipe: Recreate_E2E_Service
target:
type: VM
retry: 3
timeout: 1200
success: final_success
failure: final_failure
failure_timeout: final_failure_timeout
failure_retries: final_failure_retries
failure_exception: final_failure_exception
failure_guard: final_failure_guard
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{
"closedLoopEventClient": "DCAE.HolmesInstance",
"policyVersion": "1.0.0.5",
"policyName": "CCVPN",
"policyScope": "service=SOTNService,type=SampleType,closedLoopControlName=CL-CCVPN-d925ed73-8231-4d02-9545-db4e101f88f8",
"target_type": "VM",
"AAI": {
"vserver.vserver-name" : "TBD",
"globalSubscriberId" : "e151059a-d924-4629-845f-264db19e50b4",
"serviceType" : "SOTN",
"service-instance.service-instance-id" : "service-instance-id-example-1,service-instance-id-example-2,service-instance-id-example-3",
"service-instance.service-instance-name" : "service-instance-example-1,service-instance-example-2,service-instance-example-3",
"service-instance-example-1.input-parameters" : "...",
"service-instance-example-2.input-parameters" : "...",
"service-instance-example-3.input-parameters" : "..."
},
"closedLoopAlarmStart": 1484677482204798,
"closedLoopEventStatus": "ONSET",
"closedLoopControlName": "ControlLoop-CCVPN-2179b738-fd36-4843-a71a-a8c24c70c55b",
"version": "1.0.2",
"target": "vserver.vserver-name",
"requestID": "97964e10-686e-4790-8c45-bdfa61df770f",
"from": "DCAE"
} |
Policy Engine subscribes the unauthenticated.DCAE_CL_OUTPUT on DMAAP.
AAI Enrichment APIs
DCAE VES event A&AI enrichment for previous use cases are defined here as reference. More CCVPN related AAI API discussion can be found on this page,
Note: pnfName = Nodeid and p-interface-name = tp-id
- The query logic from tp-id through service instance is that : p-interface → vpn-vpnbinding → connectivity → service instance. Then from service-instance to 'customer-request' for service instance recreation for phase 1.
- For event from different tp-id to be correlated: p-interface → logical link, then logic link is the same from ONAP domain.
- When link down event is detected, Closed Loop needs to update logical-link/p-interface's operational-status to “DOWN” for the recreated service instance picking up new links.
The following APIs are used to support the above looking up.
Status Update
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/network-resources/network-resource/{networkId}/pnfs/pnf/{pnfName}/p-interfaces/p-interface/{ifName}
Method: PATCH
Request Body:
{
"operational-status": "some status"
}
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/logical-links/logical-link/{linkName}
Method: PATCH
Request Body:
{
"operational-status": "some status"
} |
Service Instance ID Look Up
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL:
https://<AAI host>:<AAI port>/aai/v14/network/network-resources/network-resource/{networkId}/pnfs/pnf/{pnfName}/p-interfaces?interface-name={ifName}&operational-status={status}
Method: GET
Request Body:
{
}
Response Body:
{
"results": [
{
"p-interface": {
"interface-name": "{ifName}",
"network-ref": "some ref",
"transparent": "some value",
"operational-status ": "{status}",
"speed-value": "some speed",
"relationship-list": {
"relationship" : [
{
"related-to": "vpn-binding",
"related-link": "url of vpn-binding",
"relationship-data": [
"relationship-key": "vpn-binding.vpn-id",
"relationship-value": "some id"
]
}
]
}
}
}
]
} |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/vpn-bindings?vpn-id={vpnId} Method: GET Request Body: { } Response Body: { "results": [ { "vpn-binding": { "vpn-id": "{vpnId}", "vpn-name": "some name", "access-provider-id": "provider id", "access-client-id": "client id", "access-topology-id": "topology id",com.alibaba.fastjson.JSONArray;\nimport com.alibaba.fastjson.JSONObject;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.UUID;\n\nfunction String getAdditionalField(VesAlarm a, String field) {\n List<AlarmAdditionalField> fields = a.getAlarmAdditionalInformation();\n for (AlarmAdditionalField f : fields) {\n if (f.getName().equals(field)) {\n return f.getValue();\n }\n }\n return null;\n}\n\nfunction String getLogicLink(VesAlarm alarm) {\n AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();\n return aai.getLogicLink(\n getAdditionalField(alarm, \"networkId\"),\n getAdditionalField(alarm, \"node\"),\n getAdditionalField(alarm, \"tp-id\"),\n null\n );\n}\n\nfunction boolean isCorrelated(VesAlarm a, VesAlarm b) {\n String logicLinkA = getLogicLink(a);\n if (logicLinkA == null) {\n return false;\n }\n\n String logicLinkB = getLogicLink(b);\n if (logicLinkB == null) {\n return false;\n }\n\n return logicLinkA.equals(logicLinkB);\n}\n\nfunction void updateAaiLinkStatus(String linkName, String status) {\n AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();\n Map<String, Object> body = new HashMap<String, Object>(){\n {\n put(\"operational-status\", status);\n }\n };\n aai.updateLogicLinkStatus(linkName, body);\n}\n\nfunction void updateAaiTpStatus(String networkId, String pnfName, String ifName, String status) {\n AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();\n Map<String, Object> body = new HashMap<String, Object>(){\n {\n put(\"operational-status\", status);\n }\n };\n aai.updateTerminalPointStatus(networkId, pnfName, ifName, body);\n}\n\nfunction Map<String, Object> getAdditionalResourceInfo(String networkId, String pnfName, String ifName, String status) {\n AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();\n JSONArray instances = aai.getServiceInstances(networkId, pnfName, ifName, status);\n\n Map<String, Object> ret = new HashMap<String, Object>();\n\n StringBuilder sbn = new StringBuilder();\n StringBuilder sbi = new StringBuilder();\n for(int i = 0; i < instances.size(); ++i) {\n JSONObject o = instances.getJSONObject(i);\n String name = o.getString(\"service-instance-name\");\n String id = o.getString(\"service-instance-id\");\n ret.put(id + \".input-parameters\", o.getString(\"input-parameters\"));\n sbn.append(name).append(\",\");\n sbi.append(id).append(\",\");\n }\n ret.put(\"service-instance.service-instance-name\", sbn.substring(0, sbn.length() -1).toString());\n ret.put(\"service-instance.service-instance-id\", sbi.substring(0, sbi.length() -1).toString());\n ret.put(\"vserver.vserver-name\", \"TBD\");\n ret.put(\"globalSubscriberId\", instances.getJSONObject(0).getString(\"globalSubscriberId\"));\n ret.put(\"serviceType\", instances.getJSONObject(0).getString(\"serviceType\"));\n\n return ret;\n}\n\nfunction PolicyMsg createPolicyMsg(VesAlarm alarm) {\n PolicyMsg m = new PolicyMsg();\n m.setPolicyVersion(\"1.0.0.5\");\n m.setPolicyName(\"CCVPN\");\n m.setPolicyScope(\"service=SOTNService,type=SampleType,closedLoopControlName=CL-CCVPN-d925ed73-8231-4d02-9545-db4e101f88f8\");\n m.setClosedLoopControlName(DmaapService.loopControlNames.get(\"org.onap.holmes.ccvpn\"));\n m.setRequestID(UUID.randomUUID().toString());\n m.setClosedLoopAlarmStart(alarm.getStartEpochMicrosec());\n m.setClosedLoopAlarmEnd(alarm.getLastEpochMicrosec());\n m.setTarget(\"vserver.vserver-name\");\n m.setAai(getAdditionalResourceInfo(\n getAdditionalField(alarm, \"networkId\"),\n getAdditionalField(alarm, \"node\"),\n getAdditionalField(alarm, \"tp-id\"),\n getAdditionalField(alarm, \"oper-status\")\n ));\n\n DmaapService.alarmUniqueRequestID.put(alarm.getEventId(), m.getRequestID());\n\n return m;\n}\n\nrule \"Update AAI Information\"\n no-loop true\n salience 300\n when\n $a: VesAlarm(eventName.indexOf(\"Fault_Route_Status\") != -1)\n then\n updateAaiTpStatus (\n getAdditionalField($a, \"networkId\"),\n getAdditionalField($a, \"node\"),\n getAdditionalField($a, \"tp-id\"),\n getAdditionalField($a, \"oper-status\")\n );\nend\n\nrule \"Set Up Correlation\"\n no-loop true\n salience 200\n when\n $a: VesAlarm($id: eventId, \n $start: startEpochMicrosec, \n eventName.indexOf(\"Fault_Route_Status\") != -1)\n $b: VesAlarm(eventId != $id, \n eventName.indexOf(\"Fault_Route_Status\") != -1, \n Math.abs(startEpochMicrosec - $start) < 60000)\n then\n String status = \"down\";\n if (status.equalsIgnoreCase(getAdditionalField($a, \"oper-status\")) \n && status.equalsIgnoreCase(getAdditionalField($b, \"oper-status\"))) {\n if (isCorrelated($a, $b)){\n // If any of the alarms have been marked as root, a policy message has ever been created and sent. Do NOT send it again.\n if ($a.getRootFlag() != 1 && $b.getRootFlag() != 1) {\n PolicyMsg msg = createPolicyMsg($a);\n DmaapService dmaapService = ServiceLocatorHolder.getLocator().getService(DmaapService.class);\n dmaapService.publishPolicyMsg(msg, \"unauthenticated.DCAE_CL_OUTPUT\");\n updateAaiLinkStatus(getLogicLink($a), status);\n }\n $a.setRootFlag(1);\n $b.setRootFlag(1);\n update($a);\n update($b);\n }\n }\nend\n\nrule \"Clear Alarms\"\n no-loop true\n salience 100\n when\n $a: VesAlarm(eventName.indexOf(\"Fault_Route_Status\") != -1)\n then\n if (\"up\".equalsIgnoreCase(getAdditionalField($a, \"oper-status\"))) {\n if (DmaapService.alarmUniqueRequestID.containsKey($a.getEventId())) {\n DmaapService.alarmUniqueRequestID.remove($a.getEventId());\n }\n \n //TODO: send alarm clearing message to Policy - for now it's not needed.\n //...\n \n retract($a);\n }\nend\n", "description":"This rule is designed for the correlation analysis for the CCVPN use case.", "enabled":1, "loopControlName":"ControlLoop-CCVPN-2179b738-fd36-4843-a71a-a8c24c70c55b", "ruleName":"CCVPN" } |
To illustrate, the content field in the above rule is presented as readable format in the following. We need to convert it to valid json string when uploading to Holmes.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
package org.onap.holmes.ccvpn;
dialect "java"
import org.onap.holmes.common.api.stat.VesAlarm;
import org.onap.holmes.common.api.stat.AlarmAdditionalField;
import org.onap.holmes.common.aai.AaiQuery4Ccvpn;
import org.onap.holmes.common.exception.CorrelationException;
import org.onap.holmes.common.dmaap.entity.PolicyMsg;
import org.onap.holmes.common.dmaap.DmaapService;
import org.onap.holmes.common.utils.DroolsLog;
import org.onap.holmes.common.dropwizard.ioc.utils.ServiceLocatorHolder;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
function String getAdditionalField(VesAlarm a, String field) {
List<AlarmAdditionalField> fields = a.getAlarmAdditionalInformation();
for (AlarmAdditionalField f : fields) {
if (f.getName().equals(field)) {
return f.getValue();
}
}
return null;
}
function String getLogicLink(VesAlarm alarm) {
AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();
return aai.getLogicLink(
getAdditionalField(alarm, "networkId"),
getAdditionalField(alarm, "node"),
getAdditionalField(alarm, "tp-id"),
null
);
}
function boolean isCorrelated(VesAlarm a, VesAlarm b) {
String logicLinkA = getLogicLink(a);
if (logicLinkA == null) {
return false;
}
String logicLinkB = getLogicLink(b);
if (logicLinkB == null) {
return false;
}
return logicLinkA.equals(logicLinkB);
}
function void updateAaiLinkStatus(String linkName, String status) {
AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();
Map<String, Object> body = new HashMap<String, Object>(){
{
put("operational-status", status);
}
};
aai.updateLogicLinkStatus(linkName, body);
}
function void updateAaiTpStatus(String networkId, String pnfName, String ifName, String status) {
AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();
Map<String, Object> body = new HashMap<String, Object>(){
{
put("operational-status", status);
}
};
aai.updateTerminalPointStatus(networkId, pnfName, ifName, body);
}
function Map<String, Object> getAdditionalResourceInfo(String networkId, String pnfName, String ifName, String status) {
AaiQuery4Ccvpn aai = AaiQuery4Ccvpn.newInstance();
JSONArray instances = aai.getServiceInstances(networkId, pnfName, ifName, status);
Map<String, Object> ret = new HashMap<String, Object>();
StringBuilder sbn = new StringBuilder();
StringBuilder sbi = new StringBuilder();
for(int i = 0; i < instances.size(); ++i) {
JSONObject o = instances.getJSONObject(i);
String name = o.getString("service-instance-name");
String id = o.getString("service-instance-id");
ret.put(id + ".input-parameters", o.getString("input-parameters"));
sbn.append(name).append(",");
sbi.append(id).append(",");
}
ret.put("service-instance.service-instance-name", sbn.substring(0, sbn.length() -1).toString());
ret.put("service-instance.service-instance-id", sbi.substring(0, sbi.length() -1).toString());
ret.put("vserver.vserver-name", "TBD");
ret.put("globalSubscriberId", instances.getJSONObject(0).getString("globalSubscriberId"));
ret.put("serviceType", instances.getJSONObject(0).getString("serviceType"));
return ret;
}
function PolicyMsg createPolicyMsg(VesAlarm alarm) {
PolicyMsg m = new PolicyMsg();
m.setPolicyVersion("1.0.0.5");
m.setPolicyName("CCVPN");
m.setPolicyScope("service=SOTNService,type=SampleType,closedLoopControlName=CL-CCVPN-d925ed73-8231-4d02-9545-db4e101f88f8");
m.setClosedLoopControlName(DmaapService.loopControlNames.get("org.onap.holmes.ccvpn"));
m.setRequestID(UUID.randomUUID().toString());
m.setClosedLoopAlarmStart(alarm.getStartEpochMicrosec());
m.setClosedLoopAlarmEnd(alarm.getLastEpochMicrosec());
m.setTarget("vserver.vserver-name");
m.setAai(getAdditionalResourceInfo(
getAdditionalField(alarm, "networkId"),
getAdditionalField(alarm, "node"),
getAdditionalField(alarm, "tp-id"),
getAdditionalField(alarm, "oper-status")
));
DmaapService.alarmUniqueRequestID.put(alarm.getEventId(), m.getRequestID());
return m;
}
rule "Update AAI Information"
no-loop true
salience 300
when
$a: VesAlarm(eventName.indexOf("Fault_Route_Status") != -1)
then
updateAaiTpStatus (
getAdditionalField($a, "networkId"),
getAdditionalField($a, "node"),
getAdditionalField($a, "tp-id"),
getAdditionalField($a, "oper-status")
);
end
rule "Set Up Correlation"
no-loop true
salience 200
when
$a: VesAlarm($id: eventId,
$start: startEpochMicrosec,
eventName.indexOf("Fault_Route_Status") != -1)
$b: VesAlarm(eventId != $id,
eventName.indexOf("Fault_Route_Status") != -1,
Math.abs(startEpochMicrosec - $start) < 60000)
then
String status = "down";
if (status.equalsIgnoreCase(getAdditionalField($a, "oper-status"))
&& status.equalsIgnoreCase(getAdditionalField($b, "oper-status"))) {
if (isCorrelated($a, $b)){
// If any of the alarms have been marked as root, a policy message has ever been created and sent. Do NOT send it again.
if ($a.getRootFlag() != 1 && $b.getRootFlag() != 1) {
PolicyMsg msg = createPolicyMsg($a);
DmaapService dmaapService = ServiceLocatorHolder.getLocator().getService(DmaapService.class);
dmaapService.publishPolicyMsg(msg, "unauthenticated.DCAE_CL_OUTPUT");
updateAaiLinkStatus(getLogicLink($a), status);
}
$a.setRootFlag(1);
$b.setRootFlag(1);
update($a);
update($b);
}
}
end
rule "Clear Alarms"
no-loop true
salience 100
when
$a: VesAlarm(eventName.indexOf("Fault_Route_Status") != -1)
then
if ("up".equalsIgnoreCase(getAdditionalField($a, "oper-status"))) {
if (DmaapService.alarmUniqueRequestID.containsKey($a.getEventId())) {
DmaapService.alarmUniqueRequestID.remove($a.getEventId());
}
//TODO: send alarm clearing message to Policy - for now it's not needed.
//...
retract($a);
}
end |
Rule Execution
After the correlation is done successfully, there should be a corresponding control loop event defined in the following section published on the unauthenticated.DCAE_CL_OUTPUT topic of DMaaP.
POLICY
Policy Creation
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
controlLoop:
version: 2.0.0
controlLoopName: ControlLoop-CCVPN-2179b738-fd36-4843-a71a-a8c24c70c66b
trigger_policy: unique-policy-id-16-Reroute
timeout: 3600
abatement: false
policies:
- id: unique-policy-id-16-Reroute
name: Connectivity Reroute
description:
actor: SDNC
recipe: Reroute
target:
type: VM
retry: 3
timeout: 1200
success: final_success
failure: final_failure
failure_timeout: final_failure_timeout
failure_retries: final_failure_retries
failure_exception: final_failure_exception
failure_guard: final_failure_guard
|
For now, Policy bases on the parameters looked up and encoded in by Holmes to the 'AAI' portion of the following event to invoke SDNC API to re-route the network connectivity.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{
"closedLoopEventClient": "DCAE.HolmesInstance",
"policyVersion": "1.0.0.5",
"policyName": "CCVPN",
"policyScope": "service=SOTNService,type=SampleType,closedLoopControlName=CL-CCVPN-d925ed73-8231-4d02-9545-db4e101f88f8",
"target_type": "VM",
"AAI": {
"vserver.vserver-name" : "TBD",
"globalSubscriberId" : "e151059a-d924-4629-845f-264db19e50b4",
"serviceType" : "SOTN",
"service-information.service-instance-id" : "service-instance-id-example-1",
"network-information. network-id " : "id"
},
"closedLoopAlarmStart": 1484677482204798,
"closedLoopEventStatus": "ONSET",
"closedLoopControlName": "ControlLoop-CCVPN-2179b738-fd36-4843-a71a-a8c24c70c66b",
"version": "1.0.2",
"target": "vserver.vserver-name",
"requestID": "97964e10-686e-4790-8c45-bdfa61df770f",
"from": "DCAE"
} |
Policy Engine subscribes the unauthenticated.DCAE_CL_OUTPUT on DMAAP.
AAI Enrichment APIs
DCAE VES event A&AI enrichment for previous use cases are defined here as reference. More CCVPN related AAI API discussion can be found on this page,
Note: pnfName = Nodeid and p-interface-name = tp-id
- The query logic from tp-id through service instance is that : p-interface → vpn-vpnbinding → connectivity → service instance. Then from service-instance to 'customer-request' for service instance recreation for phase 1.
- For event from different tp-id to be correlated: p-interface → logical link, then logic link is the same from ONAP domain.
- When link down event is detected, Closed Loop needs to update logical-link/p-interface's operational-status to “DOWN” for the recreated service instance picking up new links.
The following APIs are used to support the above looking up.
Status Update
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/network-resources/network-resource/{networkId}/pnfs/pnf/{pnfName}/p-interfaces/p-interface/{ifName}
Method: PATCH
Request Body:
{
"operational-status": "some status"
}
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/logical-links/logical-link/{linkName}
Method: PATCH
Request Body:
{
"operational-status": "some status"
} |
Service Instance ID Look Up
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/network-resources/network-resource/{networkId}/pnfs/pnf/{pnfName}/p-interfaces?interface-name={ifName}&operational-status={status} Method: GET Request Body: { } Response Body: { "results": [ { "p-interface": { "src-access-node-idinterface-name": "src node id{ifName}", "src-access-ltp-idnetwork-ref": "srcsome ltp idref", "dst-access-node-idtransparent": "dstsome node idvalue", "dst-access-ltp-idoperational-status ": "dst ltp id"{status}", "operationalspeed-statusvalue": "some statusspeed", "relationship-list": { "relationship" : [ { "related-to": "connectivityvpn-binding", "related-link": "url of connectivityvpn-binding", "relationship-data": [ "relationship-key": "connectivity. connectivityvpn-binding.vpn-id", "relationship-value": "some id" ] } ] } } } ] } |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/connectivities/connectivity/{connectivityIdvpn-bindings?vpn-id={vpnId} Method: GetGET Request Body: { } Response Body: { "results": [ { "connectivityvpn-binding": { "connectivityvpn-id": "{connectivityIdvpnId}", "bandwidth-profilevpn-name": "some profilename", "vpnaccess-provider-typeid": "someprovider typeid", "ciraccess-client-id": "circlient valueid", "eiraccess-topology-id": "eirtopology valueid", "cbssrc-access-node-id": "cbssrc node valueid", "ebssrc-access-ltp-id": "ebssrc ltp valueid", "color-awaredst-access-node-id": "colordst node valueid", "coupling-flagdst-access-ltp-id": "flag value"dst ltp id, "ethtoperational-svc-namestatus": "some namestatus", "accessrelationship-provider-idlist": { "provider id", "access-client-idrelationship" : [ "client id", "access-topology-id": "topology id", { "access-node-id": "node id", "accessrelated-ltp-idto": "ltp idconnectivity", "connectivity-selflink": "some URL", "cvlan related-link": "someurl of tagconnectivity", "operational-status": "some status", "relationship-listdata": [ { "relationship" : [ "relationship-key": "connectivity. connectivity-id", "relationship-value": "some id" { ] "related-to": "service-instance", } "related-link": "url of service-instance", ] } } "relationship-data": [ } ] } |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/connectivities/connectivity/{connectivityId} Method: Get Request Body: { } Response Body: { "relationship-key": "service-instance.service-instance-id","results": [ { "connectivity": { "relationship-value"connectivity-id": "some id"{connectivityId}", "bandwidth-profile-name": "some profile", "vpn-type": "some type", ] "cir": "cir value", } "eir": "eir value", "cbs": "cbs ]value", } "ebs": "ebs value", } ] | ||||||
Code Block | ||||||
| ||||||
From service-instance URL: URL: https://<AAI host>:<AAI port>/aai/v14/business/customers/customer/{global-customer-id}/service-subscriptions/service-subscription/{service-type}/service-instances?service-instance-id={servId} Derive the service-subscription URL: URL: https://<AAI host>:<AAI port>/aai/v14/business/customers/customer/{global-customer-id}/service-subscriptions/service-subscription/{service-type} Method: GET Request Body: { } Response Body: { "results": [ { "service-subscription": { "color-aware": "color value", "coupling-flag": "flag value", "etht-svc-name": "some name", "access-provider-id": "provider id", "access-client-id": "client id", "serviceaccess-topology-typeid": "{service-type}topology id", "tempaccess-ubnode-sub-account-id": "somenode sub accountid", "serviceaccess-ltp-instancesid": { "ltp id", "serviceconnectivity-instanceselflink": "some URL", [ "cvlan ": "some tag", { "operational-status": "some status", "servicerelationship-instance-idlist": "some{ id 1", "relationship" : [ "service-instance-name": "some name 1", { "environment-context": "some context 1", "workloadrelated-contextto": "some workload 1","service-instance", "relationshiprelated-listlink": { "url of service-instance", "relationship-data" : [ ] "relationship-key": "service-instance.service-instance-id", } "relationship-value": "some id" }, { ] "service-instance-id": "some id} 2", ] "service-instance-name": "some name 2", } } "environment-context": "some context 2", "workload-context": "some workload 2", ] |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
From service-instance URL: URL: https://<AAI host>:<AAI port>/aai/v14/business/customers/customer/{global-customer-id}/service-subscriptions/service-subscription/{service-type}/service-instances?service-instance-id={servId} Derive the service-subscription URL: URL: https://<AAI host>:<AAI port>/aai/v14/business/customers/customer/{global-customer-id}/service-subscriptions/service-subscription/{service-type} Method: GET Request Body: { } Response Body: { "relationship-listresults": {[ { "relationship" : ["service-subscription": { "service-type": "{service-type}", ] "temp-ub-sub-account-id": "some sub account", "service-instances": { } "service-instance": [ }, { "service-instance-id": "some id 31", "service-instance-name": "some name 31", "environment-context": "some context 31", "workload-context": "some workload 31", "relationship-list": { "relationship" : [ ] } }, ] { }, "relationshipservice-instance-listid": {"some id 2", "relationship" : [ "service-instance-name": "some name 2", "environment-context": "some context ]2", } } "workload-context": "some workload 2", } ] } For each item in results: "relationship-list": { Get item.service-subscription.service-instances - For each data in service-instances: - Get service-instance object |
Alarm Correlation
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/pnfs/pnf/{pnfName}/p-interfaces?interface-name={ifName}&operational-status={status} Method: GET Resquest Body: { } Response Body: { "relationship" : [ "results" : [ { ] "p-interface" : { "interface-name":{ifName}", }, "network-ref": "some ref", { "transparent": "some blue", "operationalservice-instance-statusid":"{status} "some id 3", "speedservice-instance-valuename" : "some name speed3", "relationship-list": "environment-context": "some context 3", "relationshipworkload-context": :"some [workload 3", "relationship-list": { "related-torelationship" : "logic-link",[ "related-link" :'url of logical-link",] } "relationship-data":[ } "relationship-key" : "logical-link.link.name", ] }, "relationship-valuelist";: "some{ name" "relationship" : [ ] ] } } ] } ] } For each }item in results: - ] } |
...
Get item.service-subscription.service-instances
- For each data in service-instances:
- Get service-instance object
|
Alarm Correlation
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/businessnetwork/customerspnfs/customerpnf/{global-custoner-idpnfName}/service-subscriptions/service-subscription/{service-type}/service-instances?service-instance-id={serviceIdp-interfaces?interface-name={ifName}&operational-status={status} Method: GET RequestResquest Body: { } Response Body: { "service-instance-idresults" : "{service-instance-id}",[ { "service-instance-name "p-interface" : { "instance name", "service-type": "some type", "service-role": "some role", "model-invariant-id": "model id", "modelinterface-version-idname":{ifName}", "model version", "input-parameters:"request parameters", // ... This is the service instance recreation input looked up by CL. "resourcenetwork-versionref": "some version" }ref", Example of response body: { "service-instance-idtransparent": "176d9eba-1662-4289-8396-0097b50fd485some blue", "service-type": "E2E Service", "service-role": "E2E Service", "model-invariant-id": "c22a9483-d2b6-49cc-b1f7-ef34c93572a1", "model-version-id": "71d0e396-e246-4c23-aa57-6da2043d6209", "input-parameters:".....;", "operational-status":"{status}", "speed-value" : // ... This is the service instance recreation input looked up by CL. "resource-version": "1528975017336" "some speed", "relationship-list": { "relationship" : [ { "related-to" : "pnflogic-link", "related-link" : "/aai/v11/network/pnfs/pnf/MME-0001",'url of logical-link", "relationship-data": [ { "relationship-key" : "pnf.pnf-idlogical-link.link.name", "relationship-value":; "176d9eba-1662-4289-8396-0097b50fd466some name" } ], "related-to-property": [ { "property-key": "pnf.pnf-name",] "property-value": "MME-0001" } ] } ] } } ] |
...
} |
Look up for 'input-parameters' by 'service-instance-id'
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/business/customers/networkcustomer/logical-links?link-name={linkName}&operational-status={status{global-custoner-id}/service-subscriptions/service-subscription/{service-type}/service-instances?service-instance-id={serviceId} Method: GET Request Body: { } Response Body: { "resultsservice-instance-id": ["{service-instance-id}", "logicservice-instance-linksname" : {"instance "link-name" : "{linkName}", "operational-status": "{status}", name", "service-type": "some type", "service-role": "some role", "model-invariant-id": "somemodel invariantid", "model-version-id" : "somemodel version", "link-id":"some id "input-parameters:"request parameters", // ... This is the "relationship-list"service instance :recreation [input looked up by { "relationship" : [ { "related-to": "p-interface", "related-link": "url of p-interface 1", "relationship-data":[CL. "resource-version": "some version" } Example of response body: { "service-instance-id": "176d9eba-1662-4289-8396-0097b50fd485", "service-type": "E2E Service", "service-role": "E2E Service", "model-invariant-id": "c22a9483-d2b6-49cc-b1f7-ef34c93572a1", "model-version-id": "71d0e396-e246-4c23-aa57-6da2043d6209", "input-parameters:".....;", // ... This is the service instance recreation input looked up by CL. "relationshipresource-keyversion": :"1528975017336" "p-interface.interface-name", relationship-list": { "relationship": [ { "relationshiprelated-valueto" : "some name 1" ] } ], }, { "relationship" : [pnf", { "related-to": "p-interface", "related-link": "url of p-interface 2", "relationship-data":[ "relationship-key" : "p-interface.interface-name", "relationship-value" : "some name 2" ] } ], } ] } |
...
"related-link": "/aai/v11/network/pnfs/pnf/MME-0001",
"relationship-data": [
{
"relationship-key": "pnf.pnf-id",
"relationship-value": "176d9eba-1662-4289-8396-0097b50fd466"
}
],
"related-to-property": [
{
"property-key": "pnf.pnf-name",
"property-value": "MME-0001"
}
]
}
]
}
}
|
Others
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
URL: https://<AAI host>:<AAI port>/aai/v14/network/logical-links?link-name={linkName}&operational-status={status}
Method: GET
{
}
Response Body:
{
"results": [
"logic-links" : {
"link-name" : "{linkName}",
"operational-status": "{status}",
"model-invariant-id": "some invariant",
"model-version-id" : "some version",
"link-id":"some id",
"relationship-list" : [
{
"relationship" : [
{
"related-to": "p-interface",
"related-link": "url of p-interface 1",
"relationship-data":[
"relationship-key" : "p-interface.interface-name",
"relationship-value" : "some name 1"
]
}
],
},
{
"relationship" : [
{
"related-to": "p-interface",
"related-link": "url of p-interface 2",
"relationship-data":[
"relationship-key" : "p-interface.interface-name",
"relationship-value" : "some name 2"
]
}
],
}
]
}
|