2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.controlloop.processor;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
29 import java.io.IOException;
30 import java.net.URLEncoder;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.time.Instant;
35 import java.util.HashMap;
36 import java.util.UUID;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
40 import org.junit.Ignore;
41 import org.junit.Test;
42 import org.kie.api.KieServices;
43 import org.kie.api.builder.KieBuilder;
44 import org.kie.api.builder.KieFileSystem;
45 import org.kie.api.builder.Message;
46 import org.kie.api.builder.ReleaseId;
47 import org.kie.api.builder.Results;
48 import org.kie.api.builder.model.KieModuleModel;
49 import org.kie.api.event.rule.AfterMatchFiredEvent;
50 import org.kie.api.event.rule.AgendaEventListener;
51 import org.kie.api.event.rule.AgendaGroupPoppedEvent;
52 import org.kie.api.event.rule.AgendaGroupPushedEvent;
53 import org.kie.api.event.rule.BeforeMatchFiredEvent;
54 import org.kie.api.event.rule.MatchCancelledEvent;
55 import org.kie.api.event.rule.MatchCreatedEvent;
56 import org.kie.api.event.rule.ObjectDeletedEvent;
57 import org.kie.api.event.rule.ObjectInsertedEvent;
58 import org.kie.api.event.rule.ObjectUpdatedEvent;
59 import org.kie.api.event.rule.RuleFlowGroupActivatedEvent;
60 import org.kie.api.event.rule.RuleFlowGroupDeactivatedEvent;
61 import org.kie.api.event.rule.RuleRuntimeEventListener;
62 import org.kie.api.runtime.KieContainer;
63 import org.kie.api.runtime.KieSession;
64 import org.kie.api.runtime.rule.FactHandle;
65 import org.onap.policy.appc.Request;
66 import org.onap.policy.appc.Response;
67 import org.onap.policy.appc.ResponseCode;
68 import org.onap.policy.appc.ResponseValue;
69 import org.onap.policy.controlloop.ControlLoopEventStatus;
70 import org.onap.policy.controlloop.ControlLoopNotificationType;
72 import org.onap.policy.controlloop.VirtualControlLoopEvent;
73 import org.onap.policy.controlloop.VirtualControlLoopNotification;
74 import org.onap.policy.controlloop.ControlLoopLogger;
75 import org.onap.policy.controlloop.impl.ControlLoopLoggerStdOutImpl;
76 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
77 import org.onap.policy.controlloop.policy.TargetType;
78 import org.onap.policy.drools.impl.PolicyEngineJUnitImpl;
79 import org.onap.policy.guard.PolicyGuard;
80 import org.onap.policy.guard.PolicyGuardYamlToXacml;
81 import com.att.research.xacml.api.pdp.PDPEngine;
82 import com.att.research.xacml.api.pdp.PDPEngineFactory;
83 import com.att.research.xacml.util.FactoryException;
84 import com.att.research.xacml.util.XACMLProperties;
86 import org.onap.policy.controlloop.policy.guard.ControlLoopGuard;
89 public class ControlLoopXacmlGuardTest {
97 this.runTest("src/main/resources/ControlLoop_Template_1707_xacml_guard.drl",
98 "src/test/resources/yaml/policy_ControlLoop_vUSP_1707.yaml",
99 "service=vUSP;resource=vCTS;type=operational",
101 "com.att.ecomp.closed_loop.vUSP:VNFS:0.0.1");
102 } catch (IOException e) {
104 fail(e.getMessage());
108 public void runTest(String droolsTemplate,
112 String policyVersion) throws IOException {
114 // Pull info from the yaml
116 final Util.Pair<ControlLoopPolicy, String> pair = Util.loadYaml(yamlFile);
118 assertNotNull(pair.a);
119 assertNotNull(pair.a.controlLoop);
120 assertNotNull(pair.a.controlLoop.controlLoopName);
121 assertTrue(pair.a.controlLoop.controlLoopName.length() > 0);
125 final KieSession kieSession = buildContainer(droolsTemplate,
126 pair.a.controlLoop.controlLoopName,
130 URLEncoder.encode(pair.b, "UTF-8"));
134 System.out.println("============");
135 System.out.println(URLEncoder.encode(pair.b, "UTF-8"));
136 System.out.println("============");
139 kieSession.addEventListener(new RuleRuntimeEventListener() {
142 public void objectInserted(ObjectInsertedEvent event) {
146 public void objectUpdated(ObjectUpdatedEvent event) {
150 public void objectDeleted(ObjectDeletedEvent event) {
153 kieSession.addEventListener(new AgendaEventListener() {
156 public void matchCreated(MatchCreatedEvent event) {
157 //System.out.println("matchCreated: " + event.getMatch().getRule());
161 public void matchCancelled(MatchCancelledEvent event) {
165 public void beforeMatchFired(BeforeMatchFiredEvent event) {
166 //System.out.println("beforeMatchFired: " + event.getMatch().getRule() + event.getMatch().getObjects());
170 public void afterMatchFired(AfterMatchFiredEvent event) {
174 public void agendaGroupPopped(AgendaGroupPoppedEvent event) {
178 public void agendaGroupPushed(AgendaGroupPushedEvent event) {
182 public void beforeRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {
186 public void afterRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {
190 public void beforeRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {
194 public void afterRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {
200 // Create XACML Guard policy from YAML
201 // We prepare 4 Guards. Notice that Rebuilds recipe has two Guards (for checking policy combining algorithm)
203 fromYamlToXacml("src/test/resources/yaml/policy_guard_vUSP_1707_appc_restart.yaml",
204 "src/main/resources/frequency_limiter_template.xml",
205 "src/test/resources/xacml/autogenerated_frequency_limiter_restart.xml");
207 fromYamlToXacml("src/test/resources/yaml/policy_guard_vUSP_1707_appc_rebuild.yaml",
208 "src/main/resources/frequency_limiter_template.xml",
209 "src/test/resources/xacml/autogenerated_frequency_limiter_rebuild.xml");
211 fromYamlToXacml("src/test/resources/yaml/policy_guard_vUSP_1707_appc_rebuild_1.yaml",
212 "src/main/resources/frequency_limiter_template.xml",
213 "src/test/resources/xacml/autogenerated_frequency_limiter_rebuild_1.xml");
215 fromYamlToXacml("src/test/resources/yaml/policy_guard_vUSP_1707_appc_migrate.yaml",
216 "src/main/resources/frequency_limiter_template.xml",
217 "src/test/resources/xacml/autogenerated_frequency_limiter_migrate.xml");
219 PolicyGuardYamlToXacml.fromYamlToXacmlBlacklist("src/test/resources/yaml/policy_guard_vUSP_1707_appc_restart_blacklist.yaml",
220 "src/main/resources/blacklist_template.xml",
221 "src/test/resources/xacml/autogenerated_blacklist.xml");
225 // Insert our globals
227 final ControlLoopLogger logger = new ControlLoopLoggerStdOutImpl();
228 kieSession.setGlobal("Logger", logger);
229 final PolicyEngineJUnitImpl engine = new PolicyEngineJUnitImpl();
230 kieSession.setGlobal("Engine", engine);
234 // Creating an embedded XACML PDP
236 final PDPEngine xacmlPdpEngine;
237 System.setProperty(XACMLProperties.XACML_PROPERTIES_NAME, "src/test/resources/xacml/xacml_guard.properties");
239 PDPEngineFactory factory;
241 factory = PDPEngineFactory.newInstance();
242 xacmlPdpEngine = factory.newEngine();
243 kieSession.setGlobal("XacmlPdpEngine", xacmlPdpEngine);
244 } catch (FactoryException e1) {
245 e1.printStackTrace();
251 // Initial fire of rules
253 kieSession.fireAllRules();
255 // Kick a thread that starts testing
257 new Thread(new Runnable() {
266 // Let's use a unique ID for the request and
267 // a unique trigger source.
269 UUID requestID = UUID.randomUUID();
270 String triggerSourceName = "foobartriggersource36";
274 sendGoodEvents(kieSession, pair.a, requestID, triggerSourceName);
275 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
277 assertTrue(obj instanceof VirtualControlLoopNotification);
278 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.ACTIVE));
280 // Give the control loop a little time to acquire the lock and publish the request
285 // "About to query Guard" notification (Querying about Restart)
286 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
288 System.out.println("\n\n####################### GOING TO QUERY GUARD about Restart!!!!!!");
289 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
290 assertTrue(obj instanceof VirtualControlLoopNotification);
291 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
294 // "Response from Guard" notification
295 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
297 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
298 assertTrue(obj instanceof VirtualControlLoopNotification);
299 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
302 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Deny")){
304 // "About to query Guard" notification (Querying about Rebuild)
305 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
307 System.out.println("\n\n####################### GOING TO QUERY GUARD about Rebuild!!!!!!");
308 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
309 assertTrue(obj instanceof VirtualControlLoopNotification);
310 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
314 // "Response from Guard" notification
315 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
317 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
318 assertTrue(obj instanceof VirtualControlLoopNotification);
319 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
322 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Deny")){
324 // "About to query Guard" notification (Querying about Migrate)
325 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
327 System.out.println("\n\n####################### GOING TO QUERY GUARD!!!!!!");
328 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
329 assertTrue(obj instanceof VirtualControlLoopNotification);
330 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
334 // "Response from Guard" notification
335 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
337 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
338 assertTrue(obj instanceof VirtualControlLoopNotification);
339 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
342 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Deny")){
343 //All the 3 operations were Denied by Guard
351 // In case one of the operations was permitted by Guard
353 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Permit")){
354 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
356 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
357 assertTrue(obj instanceof VirtualControlLoopNotification);
358 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
362 obj = engine.subscribe("UEB", "APPC-CL");
364 assertTrue(obj instanceof Request);
365 assertTrue(((Request)obj).CommonHeader.SubRequestID.equals("1"));
367 System.out.println("\n============ APP-C Got request!!! ===========\n");
369 // Ok - let's simulate ACCEPT
373 // now wait for it to finish
378 // Now we are going to success it
380 Response response = new Response((Request) obj);
381 response.Status.Code = ResponseCode.SUCCESS.getValue();
382 response.Status.Value = ResponseValue.SUCCESS.toString();
383 response.Status.Description = "AppC success";
384 kieSession.insert(response);
386 // Give it some time to process
390 // Insert the abatement event
392 sendAbatement(kieSession, pair.a, requestID, triggerSourceName);
394 // now wait for it to finish
398 // Ensure they released the lock
400 assertFalse(PolicyGuard.isLocked(TargetType.VM, triggerSourceName, requestID));
406 } catch (InterruptedException e) {
407 System.err.println("Test thread got InterruptedException " + e.getLocalizedMessage());
408 } catch (AssertionError e) {
409 System.err.println("Test thread got AssertionError " + e.getLocalizedMessage());
411 } catch (Exception e) {
412 System.err.println("Test thread got Exception " + e.getLocalizedMessage());
420 // Start firing rules
422 kieSession.fireUntilHalt();
424 // Dump working memory
426 dumpFacts(kieSession);
428 // See if there is anything left in memory
430 assertEquals(1, kieSession.getFactCount());
432 for (FactHandle handle : kieSession.getFactHandles()) {
433 Object fact = kieSession.getObject(handle);
434 assertEquals("", "com.att.ecomp.policy.controlloop.Params", fact.getClass().getName());
441 public static void dumpFacts(KieSession kieSession) {
442 System.out.println("Fact Count: " + kieSession.getFactCount());
443 for (FactHandle handle : kieSession.getFactHandles()) {
444 System.out.println("FACT: " + handle);
448 protected void sendAbatement(KieSession kieSession, ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
449 VirtualControlLoopEvent event = new VirtualControlLoopEvent();
450 event.closedLoopControlName = policy.controlLoop.controlLoopName;
451 event.requestID = requestID;
452 event.target = "vserver.vserver-name";
453 event.closedLoopAlarmStart = Instant.now().minusSeconds(5);
454 event.closedLoopAlarmEnd = Instant.now();
455 event.AAI = new HashMap<String, String>();
456 event.AAI.put("cloud-region.identity-url", "foo");
457 event.AAI.put("vserver.selflink", "bar");
458 event.AAI.put("vserver.is-closed-loop-disabled", "false");
459 event.AAI.put("generic-vnf.vnf-name", "testGenericVnfName");
460 event.closedLoopEventStatus = ControlLoopEventStatus.ABATED;
461 kieSession.insert(event);
464 protected void sendGoodEvents(KieSession kieSession, ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
465 VirtualControlLoopEvent event = new VirtualControlLoopEvent();
466 event.closedLoopControlName = policy.controlLoop.controlLoopName;
467 event.requestID = requestID;
468 event.target = "vserver.vserver-name";
469 event.closedLoopAlarmStart = Instant.now();
470 event.AAI = new HashMap<String, String>();
471 event.AAI.put("cloud-region.identity-url", "foo");
472 event.AAI.put("vserver.selflink", "bar");
473 event.AAI.put("vserver.is-closed-loop-disabled", "false");
474 event.AAI.put("vserver.vserver-name", "testGenericVnfName");
475 event.closedLoopEventStatus = ControlLoopEventStatus.ONSET;
476 kieSession.insert(event);
480 event = new ATTControlLoopEvent(event);
481 event.triggerID = "107.250.169.145_f5BigIP" + Instant.now().toEpochMilli();
482 kieSession.insert(event);
485 event = new ATTControlLoopEvent(event);
486 event.triggerID = "107.250.169.145_f5BigIP" + Instant.now().toEpochMilli();
487 kieSession.insert(event);
490 event = new ATTControlLoopEvent(event);
491 event.triggerID = "107.250.169.145_f5BigIP" + Instant.now().toEpochMilli();
492 kieSession.insert(event);
498 protected void sendBadEvents(KieSession kieSession, ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
500 // Insert a bad Event
502 VirtualControlLoopEvent event = new VirtualControlLoopEvent();
503 event.closedLoopControlName = policy.controlLoop.controlLoopName;
504 kieSession.insert(event);
507 // add the request id
509 event.requestID = requestID;
510 kieSession.insert(event);
515 event.AAI = new HashMap<String, String>();
516 event.AAI.put("cloud-region.identity-url", "foo");
517 event.AAI.put("vserver.selflink", "bar");
518 event.AAI.put("vserver.vserver-name", "vmfoo");
519 kieSession.insert(event);
522 // set a valid status
524 event.closedLoopEventStatus = ControlLoopEventStatus.ONSET;
525 kieSession.insert(event);
528 // add a trigger sourcename
530 kieSession.insert(event);
533 // add is closed-loop-disabled
535 event.AAI.put("vserver.is-closed-loop-disabled", "true");
536 kieSession.insert(event);
541 event.AAI.put("vserver.is-closed-loop-disabled", "false");
542 kieSession.insert(event);
545 // Add target, but bad.
547 event.target = "VM_BLAH";
548 kieSession.insert(event);
553 public static void fromYamlToXacml(String yamlFile, String xacmlTemplate, String xacmlPolicyOutput){
555 ControlLoopGuard yamlGuardObject = Util.loadYamlGuard(yamlFile);
556 System.out.println("actor: " + yamlGuardObject.guards.getFirst().actor);
557 System.out.println("recipe: " + yamlGuardObject.guards.getFirst().recipe);
558 System.out.println("num: " + yamlGuardObject.guards.getFirst().limit_constraints.getFirst().num);
559 System.out.println("duration: " + yamlGuardObject.guards.getFirst().limit_constraints.getFirst().duration);
560 System.out.println("time_in_range: " + yamlGuardObject.guards.getFirst().limit_constraints.getFirst().time_in_range);
562 Path xacmlTemplatePath = Paths.get(xacmlTemplate);
563 String xacmlTemplateContent;
566 xacmlTemplateContent = new String(Files.readAllBytes(xacmlTemplatePath));
568 String xacmlPolicyContent = PolicyGuardYamlToXacml.generateXacmlGuard(xacmlTemplateContent,
569 yamlGuardObject.guards.getFirst().actor,
570 yamlGuardObject.guards.getFirst().recipe,
571 yamlGuardObject.guards.getFirst().limit_constraints.getFirst().num,
572 yamlGuardObject.guards.getFirst().limit_constraints.getFirst().duration,
573 yamlGuardObject.guards.getFirst().limit_constraints.getFirst().time_in_range.get("arg2"),
574 yamlGuardObject.guards.getFirst().limit_constraints.getFirst().time_in_range.get("arg3")
578 Files.write(Paths.get(xacmlPolicyOutput), xacmlPolicyContent.getBytes());
580 } catch (IOException e) {
588 public static String generatePolicy(String ruleContents,
589 String closedLoopControlName,
592 String policyVersion,
593 String controlLoopYaml) {
595 Pattern p = Pattern.compile("\\$\\{closedLoopControlName\\}");
596 Matcher m = p.matcher(ruleContents);
597 ruleContents = m.replaceAll(closedLoopControlName);
599 p = Pattern.compile("\\$\\{policyScope\\}");
600 m = p.matcher(ruleContents);
601 ruleContents = m.replaceAll(policyScope);
603 p = Pattern.compile("\\$\\{policyName\\}");
604 m = p.matcher(ruleContents);
605 ruleContents = m.replaceAll(policyName);
607 p = Pattern.compile("\\$\\{policyVersion\\}");
608 m = p.matcher(ruleContents);
609 ruleContents = m.replaceAll(policyVersion);
611 p = Pattern.compile("\\$\\{controlLoopYaml\\}");
612 m = p.matcher(ruleContents);
613 ruleContents = m.replaceAll(controlLoopYaml);
614 System.out.println(ruleContents);
619 public static KieSession buildContainer(String droolsTemplate, String closedLoopControlName, String policyScope, String policyName, String policyVersion, String yamlSpecification) throws IOException {
621 // Get our Drools Kie factory
623 KieServices ks = KieServices.Factory.get();
625 KieModuleModel kModule = ks.newKieModuleModel();
627 System.out.println("KMODULE:" + System.lineSeparator() + kModule.toXML());
630 // Generate our drools rule from our template
632 KieFileSystem kfs = ks.newKieFileSystem();
634 kfs.writeKModuleXML(kModule.toXML());
636 Path rule = Paths.get(droolsTemplate);
637 String ruleTemplate = new String(Files.readAllBytes(rule));
638 String drlContents = generatePolicy(ruleTemplate,
639 closedLoopControlName,
645 kfs.write("src/main/resources/" + policyName + ".drl", ks.getResources().newByteArrayResource(drlContents.getBytes()));
650 KieBuilder builder = ks.newKieBuilder(kfs).buildAll();
651 Results results = builder.getResults();
652 if (results.hasMessages(Message.Level.ERROR)) {
653 for (Message msg : results.getMessages()) {
654 System.err.println(msg.toString());
656 throw new RuntimeException("Drools Rule has Errors");
658 for (Message msg : results.getMessages()) {
659 System.out.println(msg.toString());
662 // Create our kie Session and container
664 ReleaseId releaseId = ks.getRepository().getDefaultReleaseId();
665 System.out.println(releaseId);
666 KieContainer kContainer = ks.newKieContainer(releaseId);
668 return kContainer.newKieSession();