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