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