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 org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
83 import com.att.research.xacml.api.pdp.PDPEngine;
84 import com.att.research.xacml.api.pdp.PDPEngineFactory;
85 import com.att.research.xacml.util.FactoryException;
86 import com.att.research.xacml.util.XACMLProperties;
88 //import org.onap.policy.controlloop.policy.guard.ControlLoopGuard;
91 public class ControlLoopXacmlGuardTest {
92 private static final Logger logger = LoggerFactory.getLogger(ControlLoopXacmlGuardTest.class);
97 this.runTest("src/main/resources/ControlLoop_Template_xacml_guard.drl",
98 "src/test/resources/yaml/policy_ControlLoop_Service123.yaml",
99 "service=Service123;resource=Res123;type=operational",
101 "org.onap.closed_loop.Service123: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.getControlLoop());
120 assertNotNull(pair.a.getControlLoop().getControlLoopName());
121 assertTrue(pair.a.getControlLoop().getControlLoopName().length() > 0);
125 final KieSession kieSession = buildContainer(droolsTemplate,
126 pair.a.getControlLoop().getControlLoopName(),
130 URLEncoder.encode(pair.b, "UTF-8"));
134 logger.debug("============");
135 logger.debug(URLEncoder.encode(pair.b, "UTF-8"));
136 logger.debug("============");
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 //logger.debug("matchCreated: " + event.getMatch().getRule());
161 public void matchCancelled(MatchCancelledEvent event) {
165 public void beforeMatchFired(BeforeMatchFiredEvent event) {
166 //logger.debug("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 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_restart.yaml",
204 "src/main/resources/frequency_limiter_template.xml",
205 "src/test/resources/xacml/autogenerated_frequency_limiter_restart.xml");
207 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_rebuild.yaml",
208 "src/main/resources/frequency_limiter_template.xml",
209 "src/test/resources/xacml/autogenerated_frequency_limiter_rebuild.xml");
211 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_appc_rebuild_1.yaml",
212 "src/main/resources/frequency_limiter_template.xml",
213 "src/test/resources/xacml/autogenerated_frequency_limiter_rebuild_1.xml");
215 PolicyGuardYamlToXacml.fromYamlToXacml("src/test/resources/yaml/policy_guard_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_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 controlLoopLogger = new ControlLoopLoggerStdOutImpl();
228 kieSession.setGlobal("Logger", controlLoopLogger);
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 logger.debug("\n\n####################### GOING TO QUERY GUARD about Restart!!!!!!");
289 logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((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 logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((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 logger.debug("\n\n####################### GOING TO QUERY GUARD about Rebuild!!!!!!");
308 logger.debug("Rule: {} Message", ((VirtualControlLoopNotification)obj).policyName, ((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 logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((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 logger.debug("\n\n####################### GOING TO QUERY GUARD!!!!!!");
328 logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((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 logger.debug("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 logger.debug("Rule: {} Message {}", ((VirtualControlLoopNotification)obj).policyName, ((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 logger.debug("\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 logger.error("Test thread got InterruptedException ", e.getLocalizedMessage());
408 } catch (AssertionError e) {
409 logger.error("Test thread got AssertionError ", e.getLocalizedMessage());
411 } catch (Exception e) {
412 logger.error("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("", "org.onap.policy.controlloop.Params", fact.getClass().getName());
441 public static void dumpFacts(KieSession kieSession) {
442 logger.debug("Fact Count: {}", kieSession.getFactCount());
443 for (FactHandle handle : kieSession.getFactHandles()) {
444 logger.debug("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.getControlLoop().getControlLoopName();
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.getControlLoop().getControlLoopName();
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);
481 protected void sendBadEvents(KieSession kieSession, ControlLoopPolicy policy, UUID requestID, String triggerSourceName) throws InterruptedException {
483 // Insert a bad Event
485 VirtualControlLoopEvent event = new VirtualControlLoopEvent();
486 event.closedLoopControlName = policy.getControlLoop().getControlLoopName();
487 kieSession.insert(event);
490 // add the request id
492 event.requestID = requestID;
493 kieSession.insert(event);
498 event.AAI = new HashMap<String, String>();
499 event.AAI.put("cloud-region.identity-url", "foo");
500 event.AAI.put("vserver.selflink", "bar");
501 event.AAI.put("vserver.vserver-name", "vmfoo");
502 kieSession.insert(event);
505 // set a valid status
507 event.closedLoopEventStatus = ControlLoopEventStatus.ONSET;
508 kieSession.insert(event);
511 // add a trigger sourcename
513 kieSession.insert(event);
516 // add is closed-loop-disabled
518 event.AAI.put("vserver.is-closed-loop-disabled", "true");
519 kieSession.insert(event);
524 event.AAI.put("vserver.is-closed-loop-disabled", "false");
525 kieSession.insert(event);
528 // Add target, but bad.
530 event.target = "VM_BLAH";
531 kieSession.insert(event);
538 public static String generatePolicy(String ruleContents,
539 String closedLoopControlName,
542 String policyVersion,
543 String controlLoopYaml) {
545 Pattern p = Pattern.compile("\\$\\{closedLoopControlName\\}");
546 Matcher m = p.matcher(ruleContents);
547 ruleContents = m.replaceAll(closedLoopControlName);
549 p = Pattern.compile("\\$\\{policyScope\\}");
550 m = p.matcher(ruleContents);
551 ruleContents = m.replaceAll(policyScope);
553 p = Pattern.compile("\\$\\{policyName\\}");
554 m = p.matcher(ruleContents);
555 ruleContents = m.replaceAll(policyName);
557 p = Pattern.compile("\\$\\{policyVersion\\}");
558 m = p.matcher(ruleContents);
559 ruleContents = m.replaceAll(policyVersion);
561 p = Pattern.compile("\\$\\{controlLoopYaml\\}");
562 m = p.matcher(ruleContents);
563 ruleContents = m.replaceAll(controlLoopYaml);
564 logger.debug(ruleContents);
569 public static KieSession buildContainer(String droolsTemplate, String closedLoopControlName, String policyScope, String policyName, String policyVersion, String yamlSpecification) throws IOException {
571 // Get our Drools Kie factory
573 KieServices ks = KieServices.Factory.get();
575 KieModuleModel kModule = ks.newKieModuleModel();
577 logger.debug("KMODULE: {} {}", System.lineSeparator(), kModule.toXML());
580 // Generate our drools rule from our template
582 KieFileSystem kfs = ks.newKieFileSystem();
584 kfs.writeKModuleXML(kModule.toXML());
586 Path rule = Paths.get(droolsTemplate);
587 String ruleTemplate = new String(Files.readAllBytes(rule));
588 String drlContents = generatePolicy(ruleTemplate,
589 closedLoopControlName,
595 kfs.write("src/main/resources/" + policyName + ".drl", ks.getResources().newByteArrayResource(drlContents.getBytes()));
600 KieBuilder builder = ks.newKieBuilder(kfs).buildAll();
601 Results results = builder.getResults();
602 if (results.hasMessages(Message.Level.ERROR)) {
603 for (Message msg : results.getMessages()) {
604 logger.error("{}", msg);
606 throw new RuntimeException("Drools Rule has Errors");
608 for (Message msg : results.getMessages()) {
609 logger.debug("{}", msg);
612 // Create our kie Session and container
614 ReleaseId releaseId = ks.getRepository().getDefaultReleaseId();
615 logger.debug("{}", releaseId);
616 KieContainer kContainer = ks.newKieContainer(releaseId);
618 return kContainer.newKieSession();