Skip to end of metadata
Go to start of metadata



  • MSB must be installed and started and the user knows the IP address of the MSB API gateway service. Regarding how to install MSB, please go to MSB Test Environment Setup.

  • PostgreSQL(v9.5) must be installed and started. For the guidance on how to run a PostgreSQL, please refer to Offical Repository of PostgreSQL

    While setting up PostgreSQL, a database and a user named ‘holmes’ must be created. The corresponding password should be set to ‘holmespwd’. Otherwise, Holmes could not be started up successfully.

Standalone Mode


  1. Log in to the ONAP docker repo: 

    sudo docker login -u docker -p docker
  2. Start Holmes using the commands below: 

    # DB_IP - the IP address of Postgres. Do not specify the port. The default port(5432) is adopted.
    # MSB_IP - the IP address of the MSB API gateway service.
    # HOST_IP - the IP address of the host (not the docker daemon) on which the docker container is running.
    # If the 'TESTING' variable is set to '1', you're telling Holmes not to query the IP address of the Holmes containers from the DCAE config binding service but to get it directly from the environment variable 'HOST_IP'.
    sudo docker run --name holmes-rule-management -p 9101:9101 -d -e URL_JDBC=$DB_IP -e MSB_ADDR=$MSB_IP -e TESTING=1 -e HOST_IP=$HOST_IP
    sudo docker run --name holmes-engine-management -p 9102:9102 -d -e URL_JDBC=$DB_IP -e MSB_ADDR=$MSB_IP -e TESTING=1 -e HOST_IP=$HOST_IP
  3. Call the health check API to check whether Holmes has been started up successfully. 

    # the rule management component
    curl http://$MSB_IP/api/holmes-rule-mgmt/v1/healthcheck
    # the engine management component
    curl http://$MSB_IP/api/holmes-engine-mgmt/v1/healthcheck

    If the component returns "true", it is spun up successfully. Otherwise, you have to use the 'sudo docker ps' and 'sudo docker logs <container_name>' to check what happened during the service instantiation.


When Holmes is run in the standalone mode, it has to be configured manually in order to perform the sub/pub actions on DMaaP. 

  1. Subscribing 

    curl -X PUT -H 'Content-Type: application/json' \
    -d "{\"name\":\"unauthenticated.SEC_FAULT_OUTPUT\", \"url\":\"http://$DMAAP_IP:$DMAAP_PORT/events/unauthenticated.SEC_FAULT_OUTPUT\"}" \

    After setting the subscribing url, a timer task will be started using the default query interval (15s).

  2. Publishing 

    curl -X PUT -H 'Content-Type: application/json' \
    -d "{\"name\":\"unauthenticated.DCAE_CL_OUTPUT\", \"url\":\"http://$DMAAP_IP:$DMAAP_PORT/events/unauthenticated.DCAE_CL_OUTPUT\"}" \

Rule Deployment

Using Shell Commands

Then you have to deploy the rule into Holmes by calling:

curl -X PUT -H 'Content-Type: application/json' -d @holmesrule http://$MSB_IP/api/holmes-rule-mgmt/v1/rule

The rule has to be saved into a file named "holmesrule" in advance. Otherwise, you have to type in an extremely long command to deploy your rule.

If you want to update an existing rule, you have to add a field named "ruleid" into the holmesrule file using the real id returned by the API called above and then call: 

curl -X POST -H 'Content-Type: application/json' -d @holmesrule http://$MSB_IP/api/holmes-rule-mgmt/v1/rule

Here's an example rule:

Holmes Rule
    "content":"package org.onap.holmes.ccvpn;\n\ndialect \"java\"\n\nimport org.onap.holmes.common.api.stat.VesAlarm;\nimport org.onap.holmes.common.api.stat.AlarmAdditionalField;\nimport test.drools.AaiQuery4Ccvpn;\n//import org.onap.holmes.common.aai.AaiQuery4Ccvpn;\nimport org.onap.holmes.common.exception.CorrelationException;\nimport org.onap.holmes.common.dmaap.entity.PolicyMsg;\nimport org.onap.holmes.common.dmaap.DmaapService;\nimport org.onap.holmes.common.utils.DroolsLog;\nimport org.onap.holmes.common.dropwizard.ioc.utils.ServiceLocatorHolder;\n\nimport;\nimport;\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		getAdditionalField(alarm, \"oper-status\")\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 updateAaiStatus(String networkId, String pnfName, String ifName,\n		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	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(\"\");\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		updateAaiStatus (\n			getAdditionalField($a, \"networkId\"),\n			getAdditionalField($a, \"node\"),\n			getAdditionalField($a, \"tp-id\"),\n			getLogicLink($a),\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		if (\"down\".equalsIgnoreCase(getAdditionalField($a, \"oper-status\")) \n				&& \"down\".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			    	System.out.println(JSONObject.toJSONString(msg));\n			        //DmaapService dmaapService = ServiceLocatorHolder.getLocator().getService(DmaapService.class);\n			        //dmaapService.publishPolicyMsg(msg, \"unauthenticated.DCAE_CL_OUTPUT\");\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.",

Using Holmes GUI

To make things easier, from Casablanca on, Holmes provides its own GUI for rule management. Users could perform CRUD operations on all Holmes rules via GUI.

URL: https://${HOLMES_RULE_MANAGEMENT_MODULE_IP}:9104/iui/holmes/default.html

Adding a Rule

Click on the "Add" button, then a rule creation page will be displayed.

Fill in all the required fields (those with a red asterisk mark) and click on "Save".

If you want to verify whether your rule is valid, click "Check" and further information will be shown in a pop-up window.

After rules are created, they'll be listed on the main page of the rule management module.

Users could view the details of a specific rule by clicking on the "Rule Name" column. Also, some operations could be performed on the rules via the buttons provided in the "Operations" column.

DCAE Analytics App


  • No labels