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.template.demo;
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 {
96 this.runTest("src/main/resources/ControlLoop_Template_xacml_guard.drl",
97 "src/test/resources/yaml/policy_ControlLoop_Service123.yaml",
98 "service=Service123;resource=Res123;type=operational",
100 "org.onap.closed_loop.Service123:VNFS:0.0.1");
101 } catch (IOException e) {
103 fail(e.getMessage());
107 public void runTest(String droolsTemplate,
111 String policyVersion) throws IOException {
113 // Pull info from the yaml
115 final Util.Pair<ControlLoopPolicy, String> pair = Util.loadYaml(yamlFile);
117 assertNotNull(pair.a);
118 assertNotNull(pair.a.controlLoop);
119 assertNotNull(pair.a.controlLoop.controlLoopName);
120 assertTrue(pair.a.controlLoop.controlLoopName.length() > 0);
124 final KieSession kieSession = buildContainer(droolsTemplate,
125 pair.a.controlLoop.controlLoopName,
129 URLEncoder.encode(pair.b, "UTF-8"));
133 System.out.println("============");
134 System.out.println(URLEncoder.encode(pair.b, "UTF-8"));
135 System.out.println("============");
138 kieSession.addEventListener(new RuleRuntimeEventListener() {
141 public void objectInserted(ObjectInsertedEvent event) {
145 public void objectUpdated(ObjectUpdatedEvent event) {
149 public void objectDeleted(ObjectDeletedEvent event) {
152 kieSession.addEventListener(new AgendaEventListener() {
155 public void matchCreated(MatchCreatedEvent event) {
156 //System.out.println("matchCreated: " + event.getMatch().getRule());
160 public void matchCancelled(MatchCancelledEvent event) {
164 public void beforeMatchFired(BeforeMatchFiredEvent event) {
165 //System.out.println("beforeMatchFired: " + event.getMatch().getRule() + event.getMatch().getObjects());
169 public void afterMatchFired(AfterMatchFiredEvent event) {
173 public void agendaGroupPopped(AgendaGroupPoppedEvent event) {
177 public void agendaGroupPushed(AgendaGroupPushedEvent event) {
181 public void beforeRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {
185 public void afterRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {
189 public void beforeRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {
193 public void afterRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {
199 // Create XACML Guard policy from YAML
200 // We prepare 4 Guards. Notice that Rebuilds recipe has two Guards (for checking policy combining algorithm)
202 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_restart.yaml",
203 "src/main/resources/frequency_limiter_template.xml",
204 "src/test/resources/xacml/autogenerated_frequency_limiter_restart.xml");
206 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_rebuild.yaml",
207 "src/main/resources/frequency_limiter_template.xml",
208 "src/test/resources/xacml/autogenerated_frequency_limiter_rebuild.xml");
210 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_rebuild_1.yaml",
211 "src/main/resources/frequency_limiter_template.xml",
212 "src/test/resources/xacml/autogenerated_frequency_limiter_rebuild_1.xml");
214 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_migrate.yaml",
215 "src/main/resources/frequency_limiter_template.xml",
216 "src/test/resources/xacml/autogenerated_frequency_limiter_migrate.xml");
218 PolicyGuardYamlToXacml.fromYamlToXacmlBlacklist("src/test/resources/yaml/policy_guard_appc_restart_blacklist.yaml",
219 "src/main/resources/blacklist_template.xml",
220 "src/test/resources/xacml/autogenerated_blacklist.xml");
224 // Insert our globals
226 final ControlLoopLogger logger = new ControlLoopLoggerStdOutImpl();
227 kieSession.setGlobal("Logger", logger);
228 final PolicyEngineJUnitImpl engine = new PolicyEngineJUnitImpl();
229 kieSession.setGlobal("Engine", engine);
233 // Creating an embedded XACML PDP
235 final PDPEngine xacmlPdpEngine;
236 System.setProperty(XACMLProperties.XACML_PROPERTIES_NAME, "src/test/resources/xacml/xacml_guard.properties");
238 PDPEngineFactory factory;
240 factory = PDPEngineFactory.newInstance();
241 xacmlPdpEngine = factory.newEngine();
242 kieSession.setGlobal("XacmlPdpEngine", xacmlPdpEngine);
243 } catch (FactoryException e1) {
244 e1.printStackTrace();
250 // Initial fire of rules
252 kieSession.fireAllRules();
254 // Kick a thread that starts testing
256 new Thread(new Runnable() {
265 // Let's use a unique ID for the request and
266 // a unique trigger source.
268 UUID requestID = UUID.randomUUID();
269 String triggerSourceName = "foobartriggersource36";
273 sendGoodEvents(kieSession, pair.a, requestID, triggerSourceName);
274 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
276 assertTrue(obj instanceof VirtualControlLoopNotification);
277 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.ACTIVE));
279 // Give the control loop a little time to acquire the lock and publish the request
284 // "About to query Guard" notification (Querying about Restart)
285 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
287 System.out.println("\n\n####################### GOING TO QUERY GUARD about Restart!!!!!!");
288 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
289 assertTrue(obj instanceof VirtualControlLoopNotification);
290 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
293 // "Response from Guard" notification
294 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
296 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
297 assertTrue(obj instanceof VirtualControlLoopNotification);
298 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
301 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Deny")){
303 // "About to query Guard" notification (Querying about Rebuild)
304 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
306 System.out.println("\n\n####################### GOING TO QUERY GUARD about Rebuild!!!!!!");
307 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
308 assertTrue(obj instanceof VirtualControlLoopNotification);
309 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
313 // "Response from Guard" notification
314 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
316 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
317 assertTrue(obj instanceof VirtualControlLoopNotification);
318 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
321 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Deny")){
323 // "About to query Guard" notification (Querying about Migrate)
324 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
326 System.out.println("\n\n####################### GOING TO QUERY GUARD!!!!!!");
327 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
328 assertTrue(obj instanceof VirtualControlLoopNotification);
329 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
333 // "Response from Guard" notification
334 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
336 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
337 assertTrue(obj instanceof VirtualControlLoopNotification);
338 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
341 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Deny")){
342 //All the 3 operations were Denied by Guard
350 // In case one of the operations was permitted by Guard
352 if(true == ((VirtualControlLoopNotification)obj).message.contains("Guard result: Permit")){
353 obj = engine.subscribe("UEB", "POLICY-CL-MGT");
355 System.out.println("Rule: " + ((VirtualControlLoopNotification)obj).policyName +" Message: " + ((VirtualControlLoopNotification)obj).message);
356 assertTrue(obj instanceof VirtualControlLoopNotification);
357 assertTrue(((VirtualControlLoopNotification)obj).notification.equals(ControlLoopNotificationType.OPERATION));
361 obj = engine.subscribe("UEB", "APPC-CL");
363 assertTrue(obj instanceof Request);
364 assertTrue(((Request)obj).CommonHeader.SubRequestID.equals("1"));
366 System.out.println("\n============ APP-C Got request!!! ===========\n");
368 // Ok - let's simulate ACCEPT
372 // now wait for it to finish
377 // Now we are going to success it
379 Response response = new Response((Request) obj);
380 response.Status.Code = ResponseCode.SUCCESS.getValue();
381 response.Status.Value = ResponseValue.SUCCESS.toString();
382 response.Status.Description = "AppC success";
383 kieSession.insert(response);
385 // Give it some time to process
389 // Insert the abatement event
391 sendAbatement(kieSession, pair.a, requestID, triggerSourceName);
393 // now wait for it to finish
397 // Ensure they released the lock
399 assertFalse(PolicyGuard.isLocked(TargetType.VM, triggerSourceName, requestID));
405 } catch (InterruptedException e) {
406 System.err.println("Test thread got InterruptedException " + e.getLocalizedMessage());
407 } catch (AssertionError e) {
408 System.err.println("Test thread got AssertionError " + e.getLocalizedMessage());
410 } catch (Exception e) {
411 System.err.println("Test thread got Exception " + e.getLocalizedMessage());
419 // Start firing rules
421 kieSession.fireUntilHalt();
423 // Dump working memory
425 dumpFacts(kieSession);
427 // See if there is anything left in memory
429 assertEquals(1, kieSession.getFactCount());
431 for (FactHandle handle : kieSession.getFactHandles()) {
432 Object fact = kieSession.getObject(handle);
433 assertEquals("", "org.onap.policy.controlloop.Params", fact.getClass().getName());
440 public static void dumpFacts(KieSession kieSession) {
441 System.out.println("Fact Count: " + kieSession.getFactCount());
442 for (FactHandle handle : kieSession.getFactHandles()) {
443 System.out.println("FACT: " + handle);
447 protected void sendAbatement(KieSession kieSession, ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
448 VirtualControlLoopEvent event = new VirtualControlLoopEvent();
449 event.closedLoopControlName = policy.controlLoop.controlLoopName;
450 event.requestID = requestID;
451 event.target = "vserver.vserver-name";
452 event.closedLoopAlarmStart = Instant.now().minusSeconds(5);
453 event.closedLoopAlarmEnd = Instant.now();
454 event.AAI = new HashMap<String, String>();
455 event.AAI.put("cloud-region.identity-url", "foo");
456 event.AAI.put("vserver.selflink", "bar");
457 event.AAI.put("vserver.is-closed-loop-disabled", "false");
458 event.AAI.put("generic-vnf.vnf-name", "testGenericVnfName");
459 event.closedLoopEventStatus = ControlLoopEventStatus.ABATED;
460 kieSession.insert(event);
463 protected void sendGoodEvents(KieSession kieSession, ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
464 VirtualControlLoopEvent event = new VirtualControlLoopEvent();
465 event.closedLoopControlName = policy.controlLoop.controlLoopName;
466 event.requestID = requestID;
467 event.target = "vserver.vserver-name";
468 event.closedLoopAlarmStart = Instant.now();
469 event.AAI = new HashMap<String, String>();
470 event.AAI.put("cloud-region.identity-url", "foo");
471 event.AAI.put("vserver.selflink", "bar");
472 event.AAI.put("vserver.is-closed-loop-disabled", "false");
473 event.AAI.put("vserver.vserver-name", "testGenericVnfName");
474 event.closedLoopEventStatus = ControlLoopEventStatus.ONSET;
475 kieSession.insert(event);
480 protected void sendBadEvents(KieSession kieSession, ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
482 // Insert a bad Event
484 VirtualControlLoopEvent event = new VirtualControlLoopEvent();
485 event.closedLoopControlName = policy.controlLoop.controlLoopName;
486 kieSession.insert(event);
489 // add the request id
491 event.requestID = requestID;
492 kieSession.insert(event);
497 event.AAI = new HashMap<String, String>();
498 event.AAI.put("cloud-region.identity-url", "foo");
499 event.AAI.put("vserver.selflink", "bar");
500 event.AAI.put("vserver.vserver-name", "vmfoo");
501 kieSession.insert(event);
504 // set a valid status
506 event.closedLoopEventStatus = ControlLoopEventStatus.ONSET;
507 kieSession.insert(event);
510 // add a trigger sourcename
512 kieSession.insert(event);
515 // add is closed-loop-disabled
517 event.AAI.put("vserver.is-closed-loop-disabled", "true");
518 kieSession.insert(event);
523 event.AAI.put("vserver.is-closed-loop-disabled", "false");
524 kieSession.insert(event);
527 // Add target, but bad.
529 event.target = "VM_BLAH";
530 kieSession.insert(event);
537 public static String generatePolicy(String ruleContents,
538 String closedLoopControlName,
541 String policyVersion,
542 String controlLoopYaml) {
544 Pattern p = Pattern.compile("\\$\\{closedLoopControlName\\}");
545 Matcher m = p.matcher(ruleContents);
546 ruleContents = m.replaceAll(closedLoopControlName);
548 p = Pattern.compile("\\$\\{policyScope\\}");
549 m = p.matcher(ruleContents);
550 ruleContents = m.replaceAll(policyScope);
552 p = Pattern.compile("\\$\\{policyName\\}");
553 m = p.matcher(ruleContents);
554 ruleContents = m.replaceAll(policyName);
556 p = Pattern.compile("\\$\\{policyVersion\\}");
557 m = p.matcher(ruleContents);
558 ruleContents = m.replaceAll(policyVersion);
560 p = Pattern.compile("\\$\\{controlLoopYaml\\}");
561 m = p.matcher(ruleContents);
562 ruleContents = m.replaceAll(controlLoopYaml);
563 System.out.println(ruleContents);
568 public static KieSession buildContainer(String droolsTemplate, String closedLoopControlName, String policyScope, String policyName, String policyVersion, String yamlSpecification) throws IOException {
570 // Get our Drools Kie factory
572 KieServices ks = KieServices.Factory.get();
574 KieModuleModel kModule = ks.newKieModuleModel();
576 System.out.println("KMODULE:" + System.lineSeparator() + kModule.toXML());
579 // Generate our drools rule from our template
581 KieFileSystem kfs = ks.newKieFileSystem();
583 kfs.writeKModuleXML(kModule.toXML());
585 Path rule = Paths.get(droolsTemplate);
586 String ruleTemplate = new String(Files.readAllBytes(rule));
587 String drlContents = generatePolicy(ruleTemplate,
588 closedLoopControlName,
594 kfs.write("src/main/resources/" + policyName + ".drl", ks.getResources().newByteArrayResource(drlContents.getBytes()));
599 KieBuilder builder = ks.newKieBuilder(kfs).buildAll();
600 Results results = builder.getResults();
601 if (results.hasMessages(Message.Level.ERROR)) {
602 for (Message msg : results.getMessages()) {
603 System.err.println(msg.toString());
605 throw new RuntimeException("Drools Rule has Errors");
607 for (Message msg : results.getMessages()) {
608 System.out.println(msg.toString());
611 // Create our kie Session and container
613 ReleaseId releaseId = ks.getRepository().getDefaultReleaseId();
614 System.out.println(releaseId);
615 KieContainer kContainer = ks.newKieContainer(releaseId);
617 return kContainer.newKieSession();