891c7f845246501ef8ec1b108ffa110abbe7fbd2
[clamp.git] / src / main / java / org / onap / clamp / clds / client / req / policy / OperationalPolicyReq.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
6  *                             reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END============================================
20  * ===================================================================
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23
24 package org.onap.clamp.clds.client.req.policy;
25
26 import com.att.eelf.configuration.EELFLogger;
27 import com.att.eelf.configuration.EELFLogger.Level;
28 import com.att.eelf.configuration.EELFManager;
29 import com.fasterxml.jackson.databind.JsonNode;
30 import com.fasterxml.jackson.databind.node.ObjectNode;
31
32 import java.io.UnsupportedEncodingException;
33 import java.net.URLEncoder;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Map;
39
40 import javax.ws.rs.BadRequestException;
41
42 import org.onap.clamp.clds.config.ClampProperties;
43 import org.onap.clamp.clds.model.properties.Global;
44 import org.onap.clamp.clds.model.properties.ModelProperties;
45 import org.onap.clamp.clds.model.properties.PolicyChain;
46 import org.onap.clamp.clds.model.properties.PolicyItem;
47 import org.onap.clamp.clds.model.properties.Tca;
48 import org.onap.policy.api.AttributeType;
49 import org.onap.policy.controlloop.policy.OperationsAccumulateParams;
50 import org.onap.policy.controlloop.policy.Policy;
51 import org.onap.policy.controlloop.policy.PolicyResult;
52 import org.onap.policy.controlloop.policy.Target;
53 import org.onap.policy.controlloop.policy.TargetType;
54 import org.onap.policy.controlloop.policy.builder.BuilderException;
55 import org.onap.policy.controlloop.policy.builder.ControlLoopPolicyBuilder;
56 import org.onap.policy.controlloop.policy.builder.Message;
57 import org.onap.policy.controlloop.policy.builder.Results;
58 import org.onap.policy.sdc.Resource;
59 import org.onap.policy.sdc.ResourceType;
60 import org.onap.policy.sdc.Service;
61
62 /**
63  * Construct an Operational Policy request given CLDS objects.
64  */
65 public class OperationalPolicyReq {
66
67     private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicyReq.class);
68
69     protected OperationalPolicyReq() {
70     }
71
72     /**
73      * Format Operational Policy attributes.
74      *
75      * @param refProp
76      * @param prop
77      * @param modelElementId
78      * @param policyChain
79      * @return
80      * @throws BuilderException
81      * @throws UnsupportedEncodingException
82      */
83     public static Map<AttributeType, Map<String, String>> formatAttributes(ClampProperties refProp,
84             ModelProperties prop, String modelElementId, PolicyChain policyChain)
85             throws BuilderException, UnsupportedEncodingException {
86         Global global = prop.getGlobal();
87         prop.setCurrentModelElementId(modelElementId);
88         prop.setPolicyUniqueId(policyChain.getPolicyId());
89         String templateName = "";
90         String operationTopic = "";
91         String notificationTopic = "";
92         String controller = "";
93         Tca tca = prop.getType(Tca.class);
94         if (tca != null && tca.isFound()) {
95             if (global.getActionSet().equalsIgnoreCase("enbRecipe")) {
96                 templateName = refProp.getStringValue("op.eNodeB.templateName", global.getService());
97                 operationTopic = refProp.getStringValue("op.eNodeB.operationTopic", global.getService());
98                 notificationTopic = refProp.getStringValue("op.eNodeB.notificationTopic", global.getService());
99                 controller = refProp.getStringValue("op.eNodeB.controller", global.getService());
100             } else {
101                 templateName = refProp.getStringValue("op.templateName", global.getService());
102                 operationTopic = refProp.getStringValue("op.operationTopic", global.getService());
103                 notificationTopic = refProp.getStringValue("op.notificationTopic", global.getService());
104                 controller = refProp.getStringValue("op.controller", global.getService());
105             }
106         }
107         String recipeTopic = refProp.getStringValue("op.recipeTopic", global.getService());
108         // ruleAttributes
109         logger.info("templateName=" + templateName);
110         logger.info("notificationTopic=" + notificationTopic);
111         Map<String, String> ruleAttributes = new HashMap<>();
112         ruleAttributes.put("templateName", templateName);
113         ruleAttributes.put("ClosedLoopControlName", prop.getControlNameAndPolicyUniqueId());
114         ruleAttributes.put("NotificationTopic", notificationTopic);
115         if (operationTopic == null || operationTopic.isEmpty()) {
116             logger.info("recipeTopic=" + recipeTopic);
117             // if no operationTopic, then don't format yaml - use first policy
118             // from list
119             PolicyItem policyItem = policyChain.getPolicyItems().get(0);
120             ruleAttributes.put("RecipeTopic", recipeTopic);
121             String recipe = policyItem.getRecipe();
122             String maxRetries = String.valueOf(policyItem.getMaxRetries());
123             String retryTimeLimit = String.valueOf(policyItem.getRetryTimeLimit());
124             String targetResourceId = String.valueOf(policyItem.getTargetResourceId());
125             logger.info("recipe=" + recipe);
126             logger.info("maxRetries=" + maxRetries);
127             logger.info("retryTimeLimit=" + retryTimeLimit);
128             logger.info("targetResourceId=" + targetResourceId);
129             ruleAttributes.put("Recipe", recipe);
130             ruleAttributes.put("MaxRetries", maxRetries);
131             ruleAttributes.put("RetryTimeLimit", retryTimeLimit);
132             ruleAttributes.put("ResourceId", targetResourceId);
133         } else {
134             logger.info("operationTopic=" + operationTopic);
135             // format yaml
136             String yaml = (tca != null && tca.isFound()) ? formateNodeBYaml(refProp, prop, modelElementId, policyChain)
137                     : formatYaml(refProp, prop, modelElementId, policyChain);
138             ruleAttributes.put("OperationTopic", operationTopic);
139             ruleAttributes.put("ControlLoopYaml", yaml);
140         }
141         // matchingAttributes
142         Map<String, String> matchingAttributes = new HashMap<>();
143         matchingAttributes.put("controller", controller);
144         Map<AttributeType, Map<String, String>> attributes = new HashMap<>();
145         attributes.put(AttributeType.RULE, ruleAttributes);
146         attributes.put(AttributeType.MATCHING, matchingAttributes);
147         return attributes;
148     }
149
150     /**
151      * Format Operational OpenLoop Policy yaml.
152      * 
153      * @param refProp
154      * @param prop
155      * @param modelElementId
156      * @param policyChain
157      * @return
158      * @throws BuilderException
159      * @throws UnsupportedEncodingException
160      */
161     protected static String formatOpenLoopYaml(ClampProperties refProp, ModelProperties prop, String modelElementId,
162             PolicyChain policyChain) throws BuilderException, UnsupportedEncodingException {
163         // get property objects
164         Global global = prop.getGlobal();
165         prop.setCurrentModelElementId(modelElementId);
166         prop.setPolicyUniqueId(policyChain.getPolicyId());
167         // convert values to SDC objects
168         Service service = new Service(global.getService());
169         Resource[] vfResources = convertToResource(global.getResourceVf(), ResourceType.VF);
170         // create builder
171         ControlLoopPolicyBuilder builder = ControlLoopPolicyBuilder.Factory.buildControlLoop(prop.getControlName(),
172                 policyChain.getTimeout(), service, vfResources);
173         // builder.setTriggerPolicy(refProp.getStringValue("op.openloop.policy"));
174         // Build the specification
175         Results results = builder.buildSpecification();
176         validate(results);
177         return URLEncoder.encode(results.getSpecification(), "UTF-8");
178     }
179
180     /**
181      * Format Operational Policy yaml.
182      *
183      * @param refProp
184      * @param prop
185      * @param modelElementId
186      * @param policyChain
187      * @return
188      * @throws BuilderException
189      * @throws UnsupportedEncodingException
190      */
191     protected static String formatYaml(ClampProperties refProp, ModelProperties prop, String modelElementId,
192             PolicyChain policyChain) throws BuilderException, UnsupportedEncodingException {
193         // get property objects
194         Global global = prop.getGlobal();
195         prop.setCurrentModelElementId(modelElementId);
196         prop.setPolicyUniqueId(policyChain.getPolicyId());
197         // convert values to SDC objects
198         Service service = new Service(global.getService());
199         Resource[] vfResources = convertToResource(global.getResourceVf(), ResourceType.VF);
200         Resource[] vfcResources = convertToResource(global.getResourceVfc(), ResourceType.VFC);
201         // create builder
202         ControlLoopPolicyBuilder builder = ControlLoopPolicyBuilder.Factory.buildControlLoop(prop.getControlName(),
203                 policyChain.getTimeout(), service, vfResources);
204         builder.addResource(vfcResources);
205         // process each policy
206         Map<String, Policy> policyObjMap = new HashMap<>();
207         List<PolicyItem> policyItemList = orderParentFirst(policyChain.getPolicyItems());
208         for (PolicyItem policyItem : policyItemList) {
209             String policyName = policyItem.getRecipe() + " Policy";
210             Target target = new Target();
211             target.setType(TargetType.VM);
212             target.setResourceID(policyItem.getTargetResourceId());
213             Policy policyObj;
214             if (policyItemList.indexOf(policyItem) == 0) {
215                 String policyDescription = policyItem.getRecipe()
216                         + " Policy - the trigger (no parent) policy - created by CLDS";
217                 policyObj = builder.setTriggerPolicy(policyName, policyDescription,
218                         refProp.getStringValue("op.policy.appc"), target, policyItem.getRecipe(), null,
219                         policyItem.getMaxRetries(), policyItem.getRetryTimeLimit());
220             } else {
221                 Policy parentPolicyObj = policyObjMap.get(policyItem.getParentPolicy());
222                 String policyDescription = policyItem.getRecipe() + " Policy - triggered conditionally by "
223                         + parentPolicyObj.getName() + " - created by CLDS";
224                 policyObj = builder.setPolicyForPolicyResult(policyName, policyDescription,
225                         refProp.getStringValue("op.policy.appc"), target, policyItem.getRecipe(), null,
226                         policyItem.getMaxRetries(), policyItem.getRetryTimeLimit(), parentPolicyObj.getId(),
227                         convertToPolicyResult(policyItem.getParentPolicyConditions()));
228                 logger.info("policyObj.id=" + policyObj.getId() + "; parentPolicyObj.id=" + parentPolicyObj.getId());
229             }
230             policyObjMap.put(policyItem.getId(), policyObj);
231         }
232         // Build the specification
233         Results results = builder.buildSpecification();
234         validate(results);
235         return URLEncoder.encode(results.getSpecification(), "UTF-8");
236     }
237
238     /**
239      * Format Operational Policy yaml.
240      *
241      * @param refProp
242      * @param prop
243      * @param modelElementId
244      * @param policyChain
245      * @return
246      * @throws BuilderException
247      * @throws UnsupportedEncodingException
248      */
249     protected static String formateNodeBYaml(ClampProperties refProp, ModelProperties prop, String modelElementId,
250             PolicyChain policyChain) throws BuilderException, UnsupportedEncodingException {
251         // get property objects
252         Global global = prop.getGlobal();
253         prop.setCurrentModelElementId(modelElementId);
254         prop.setPolicyUniqueId(policyChain.getPolicyId());
255         // convert values to SDC objects
256         Service service = new Service(global.getService());
257         Resource[] vfResources = convertToResource(global.getResourceVf(), ResourceType.VF);
258         Resource[] vfcResources = convertToResource(global.getResourceVfc(), ResourceType.VFC);
259         // create builder
260         ControlLoopPolicyBuilder builder = ControlLoopPolicyBuilder.Factory.buildControlLoop(prop.getControlName(),
261                 policyChain.getTimeout(), service, vfResources);
262         builder.addResource(vfcResources);
263         // process each policy
264         Map<String, Policy> policyObjMap = new HashMap<>();
265         List<PolicyItem> policyItemList = addAOTSActorRecipe(refProp, global.getService(),
266                 policyChain.getPolicyItems());
267         Policy lastPolicyObj = new Policy();
268         for (PolicyItem policyItem : policyItemList) {
269             Target target = new Target();
270             target.setType(TargetType.VM);
271             target.setResourceID(policyItem.getTargetResourceId());
272             String policyName = policyItem.getRecipe() + " Policy";
273             Policy policyObj;
274             if (policyItemList.indexOf(policyItem) == 0) {
275                 // To set up time window payload for trigger policy
276                 Map<String, String> payloadMap = new HashMap<>();
277                 payloadMap.put("timeWindow", refProp.getStringValue("op.eNodeB.timeWindow"));
278                 String policyDescription = policyItem.getRecipe()
279                         + " Policy - the trigger (no parent) policy - created by CLDS";
280                 policyObj = builder.setTriggerPolicy(policyName, policyDescription, policyItem.getActor(), target,
281                         policyItem.getRecipe(), payloadMap, policyItem.getMaxRetries(), policyItem.getRetryTimeLimit());
282             } else {
283                 Policy parentPolicyObj = policyObjMap.get(policyItem.getParentPolicy());
284                 String policyDescription = policyItem.getRecipe() + " Policy - triggered conditionally by "
285                         + parentPolicyObj.getName() + " - created by CLDS";
286                 policyObj = builder.setPolicyForPolicyResult(policyName, policyDescription, policyItem.getActor(),
287                         target, policyItem.getRecipe(), null, policyItem.getMaxRetries(),
288                         policyItem.getRetryTimeLimit(), parentPolicyObj.getId(),
289                         convertToPolicyResult(policyItem.getParentPolicyConditions()));
290                 lastPolicyObj = policyObj;
291                 logger.info("policyObj.id=" + policyObj.getId() + "; parentPolicyObj.id=" + parentPolicyObj.getId());
292             }
293             policyObjMap.put(policyItem.getId(), policyObj);
294         }
295         // To set up operations accumulate params
296         OperationsAccumulateParams operationsAccumulateParams = new OperationsAccumulateParams();
297         operationsAccumulateParams.setLimit(Integer.valueOf(refProp.getStringValue("op.eNodeB.limit")));
298         operationsAccumulateParams.setPeriod(refProp.getStringValue("op.eNodeB.period"));
299         builder.addOperationsAccumulateParams(lastPolicyObj.getId(), operationsAccumulateParams);
300         // Build the specification
301         Results results = builder.buildSpecification();
302         validate(results);
303         return URLEncoder.encode(results.getSpecification(), "UTF-8");
304     }
305
306     private static void validate(Results results) {
307         if (results.isValid()) {
308             logger.info("results.getSpecification()=" + results.getSpecification());
309         } else {
310             // throw exception with error info
311             StringBuilder sb = new StringBuilder();
312             sb.append("Operation Policy validation problem: ControlLoopPolicyBuilder failed with following messages: ");
313             for (Message message : results.getMessages()) {
314                 sb.append(message.getMessage());
315                 sb.append("; ");
316             }
317             throw new BadRequestException(sb.toString());
318         }
319     }
320
321     /**
322      * Adding AOTS actor and other recipe for yaml
323      *
324      * @param inOrigList
325      * @return
326      */
327     private static List<PolicyItem> addAOTSActorRecipe(ClampProperties refProp, String service,
328             List<PolicyItem> inOrigList) {
329         List<PolicyItem> outList = new ArrayList<>();
330         try {
331             PolicyItem policyItem = inOrigList.get(0);
332             ObjectNode rootNode = (ObjectNode) refProp.getJsonTemplate("op.eNodeB.recipe", service);
333             Iterator<JsonNode> itr = rootNode.get("eNodeBRecipes").elements();
334             while (itr.hasNext()) {
335                 PolicyItem policyItemObj = (PolicyItem) policyItem.clone();
336                 JsonNode recipeNode = itr.next();
337                 policyItemObj.setId(recipeNode.path("Recipe").asText());
338                 policyItemObj.setActor(recipeNode.path("Actor").asText());
339                 policyItemObj.setRecipe(recipeNode.path("Recipe").asText());
340                 policyItemObj.setParentPolicy(recipeNode.path("ParentPolicy").asText());
341                 if (!recipeNode.path("Retry").asText().isEmpty()) {
342                     policyItemObj.setMaxRetries(Integer.parseInt(recipeNode.path("Retry").asText()));
343                 }
344                 if (!recipeNode.path("TimeLimit").asText().isEmpty()) {
345                     policyItemObj.setRetryTimeLimit(Integer.parseInt(recipeNode.path("TimeLimit").asText()));
346                 }
347                 if (!recipeNode.path("PPConditions").asText().isEmpty()) {
348                     List<String> parentPolicyConditions = new ArrayList<>();
349                     for (String ppCondition : recipeNode.path("PPConditions").asText().split(",")) {
350                         parentPolicyConditions.add(ppCondition);
351                     }
352                     policyItemObj.setParentPolicyConditions(parentPolicyConditions);
353                 }
354                 outList.add(policyItemObj);
355             }
356         } catch (Exception e) {
357             logger.log(Level.ERROR, "Error", e);
358         }
359         return outList;
360     }
361
362     /**
363      * Order list of PolicyItems so that parents come before any of their
364      * children
365      *
366      * @param inOrigList
367      * @return
368      */
369     private static List<PolicyItem> orderParentFirst(List<PolicyItem> inOrigList) {
370         List<PolicyItem> inList = new ArrayList<>();
371         inList.addAll(inOrigList);
372         List<PolicyItem> outList = new ArrayList<>();
373         int prevSize = 0;
374         while (!inList.isEmpty()) {
375             // check if there's a loop in the policy chain (the inList should
376             // have been reduced by at least one)
377             if (inList.size() == prevSize) {
378                 throw new BadRequestException("Operation Policy validation problem: loop in Operation Policy chain");
379             }
380             prevSize = inList.size();
381             // the following loop should remove at least one PolicyItem from the
382             // inList
383             Iterator<PolicyItem> inListItr = inList.iterator();
384             while (inListItr.hasNext()) {
385                 PolicyItem inItem = inListItr.next();
386                 // check for trigger policy (no parent)
387                 String parent = inItem.getParentPolicy();
388                 if (parent == null || parent.length() == 0) {
389                     if (!outList.isEmpty()) {
390                         throw new BadRequestException(
391                                 "Operation Policy validation problem: more than one trigger policy");
392                     } else {
393                         outList.add(inItem);
394                         inListItr.remove();
395                     }
396                 } else {
397                     // check if this PolicyItem's parent has been processed
398                     for (PolicyItem outItem : outList) {
399                         if (outItem.getId().equals(parent)) {
400                             // if the inItem parent is already in the outList,
401                             // then add inItem to outList and remove from inList
402                             outList.add(inItem);
403                             inListItr.remove();
404                             break;
405                         }
406                     }
407                 }
408             }
409         }
410         return outList;
411     }
412
413     /**
414      * Convert a List of resource strings to an array of Resource objects.
415      *
416      * @param stringList
417      * @param resourceType
418      * @return
419      */
420     private static Resource[] convertToResource(List<String> stringList, ResourceType resourceType) {
421         if (stringList == null || stringList.isEmpty()) {
422             return new Resource[0];
423         }
424         return stringList.stream().map(stringElem -> new Resource(stringElem, resourceType)).toArray(Resource[]::new);
425     }
426
427     /**
428      * Convert a List of policy result strings to an array of PolicyResult
429      * objects.
430      *
431      * @param prList
432      * @return
433      */
434     private static PolicyResult[] convertToPolicyResult(List<String> prList) {
435         if (prList == null || prList.isEmpty()) {
436             return new PolicyResult[0];
437         }
438         return prList.stream().map(stringElem -> PolicyResult.toResult(stringElem)).toArray(PolicyResult[]::new);
439     }
440 }