cleaned up clds service code
[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  * Modifications copyright (c) 2018 Nokia
21  * ===================================================================
22  * 
23  */
24
25 package org.onap.clamp.clds.client.req.policy;
26
27 import com.att.eelf.configuration.EELFLogger;
28 import com.att.eelf.configuration.EELFManager;
29
30 import java.io.UnsupportedEncodingException;
31 import java.net.URLEncoder;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37
38 import javax.ws.rs.BadRequestException;
39
40 import org.onap.clamp.clds.config.ClampProperties;
41 import org.onap.clamp.clds.model.properties.Global;
42 import org.onap.clamp.clds.model.properties.ModelProperties;
43 import org.onap.clamp.clds.model.properties.PolicyChain;
44 import org.onap.clamp.clds.model.properties.PolicyItem;
45 import org.onap.policy.api.AttributeType;
46 import org.onap.policy.controlloop.policy.Policy;
47 import org.onap.policy.controlloop.policy.PolicyResult;
48 import org.onap.policy.controlloop.policy.Target;
49 import org.onap.policy.controlloop.policy.TargetType;
50 import org.onap.policy.controlloop.policy.builder.BuilderException;
51 import org.onap.policy.controlloop.policy.builder.ControlLoopPolicyBuilder;
52 import org.onap.policy.controlloop.policy.builder.Message;
53 import org.onap.policy.controlloop.policy.builder.Results;
54 import org.onap.policy.sdc.Resource;
55 import org.onap.policy.sdc.ResourceType;
56 import org.onap.policy.sdc.Service;
57
58 /**
59  * Construct an Operational Policy request given CLDS objects.
60  */
61 public class OperationalPolicyReq {
62
63     private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicyReq.class);
64
65     protected OperationalPolicyReq() {
66     }
67
68     /**
69      * Format Operational Policy attributes.
70      *
71      * @param refProp
72      * @param prop
73      * @param modelElementId
74      * @param policyChain
75      * @return
76      * @throws BuilderException
77      * @throws UnsupportedEncodingException
78      */
79     public static Map<AttributeType, Map<String, String>> formatAttributes(ClampProperties refProp,
80             ModelProperties prop, String modelElementId, PolicyChain policyChain)
81             throws BuilderException, UnsupportedEncodingException {
82         Global global = prop.getGlobal();
83         prop.setCurrentModelElementId(modelElementId);
84         prop.setPolicyUniqueId(policyChain.getPolicyId());
85         String templateName = refProp.getStringValue("op.templateName", global.getService());
86         String operationTopic = refProp.getStringValue("op.operationTopic", global.getService());
87         String notificationTopic = refProp.getStringValue("op.notificationTopic", global.getService());
88         String controller = refProp.getStringValue("op.controller", global.getService());
89         String recipeTopic = refProp.getStringValue("op.recipeTopic", global.getService());
90         // ruleAttributes
91         logger.info("templateName=" + templateName);
92         logger.info("notificationTopic=" + notificationTopic);
93         Map<String, String> ruleAttributes = new HashMap<>();
94         ruleAttributes.put("templateName", templateName);
95         ruleAttributes.put("closedLoopControlName", prop.getControlNameAndPolicyUniqueId());
96         ruleAttributes.put("notificationTopic", notificationTopic);
97         if (operationTopic == null || operationTopic.isEmpty()) {
98             logger.info("recipeTopic=" + recipeTopic);
99             // if no operationTopic, then don't format yaml - use first policy
100             // from list
101             PolicyItem policyItem = policyChain.getPolicyItems().get(0);
102             ruleAttributes.put("RecipeTopic", recipeTopic);
103             String recipe = policyItem.getRecipe();
104             String maxRetries = String.valueOf(policyItem.getMaxRetries());
105             String retryTimeLimit = String.valueOf(policyItem.getRetryTimeLimit());
106             String targetResourceId = String.valueOf(policyItem.getTargetResourceId());
107             logger.info("recipe=" + recipe);
108             logger.info("maxRetries=" + maxRetries);
109             logger.info("retryTimeLimit=" + retryTimeLimit);
110             logger.info("targetResourceId=" + targetResourceId);
111             ruleAttributes.put("Recipe", recipe);
112             ruleAttributes.put("MaxRetries", maxRetries);
113             ruleAttributes.put("RetryTimeLimit", retryTimeLimit);
114             ruleAttributes.put("ResourceId", targetResourceId);
115         } else {
116             logger.info("operationTopic=" + operationTopic);
117             // format yaml
118             String yaml = formatYaml(refProp, prop, modelElementId, policyChain);
119             ruleAttributes.put("operationTopic", operationTopic);
120             ruleAttributes.put("controlLoopYaml", yaml);
121         }
122         // matchingAttributes
123         Map<String, String> matchingAttributes = new HashMap<>();
124         matchingAttributes.put("controller", controller);
125         Map<AttributeType, Map<String, String>> attributes = new HashMap<>();
126         attributes.put(AttributeType.RULE, ruleAttributes);
127         attributes.put(AttributeType.MATCHING, matchingAttributes);
128         return attributes;
129     }
130
131     /**
132      * Format Operational OpenLoop Policy yaml.
133      * 
134      * @param refProp
135      * @param prop
136      * @param modelElementId
137      * @param policyChain
138      * @return
139      * @throws BuilderException
140      * @throws UnsupportedEncodingException
141      */
142     protected static String formatOpenLoopYaml(ClampProperties refProp, ModelProperties prop, String modelElementId,
143             PolicyChain policyChain) throws BuilderException, UnsupportedEncodingException {
144         // get property objects
145         Global global = prop.getGlobal();
146         prop.setCurrentModelElementId(modelElementId);
147         prop.setPolicyUniqueId(policyChain.getPolicyId());
148         // convert values to SDC objects
149         Service service = new Service(global.getService());
150         Resource[] vfResources = convertToResource(global.getResourceVf(), ResourceType.VF);
151         // create builder
152         ControlLoopPolicyBuilder builder = ControlLoopPolicyBuilder.Factory.buildControlLoop(prop.getControlName(),
153                 policyChain.getTimeout(), service, vfResources);
154         // builder.setTriggerPolicy(refProp.getStringValue("op.openloop.policy"));
155         // Build the specification
156         Results results = builder.buildSpecification();
157         validate(results);
158         return URLEncoder.encode(results.getSpecification(), "UTF-8");
159     }
160
161     /**
162      * Format Operational Policy yaml.
163      *
164      * @param refProp
165      * @param prop
166      * @param modelElementId
167      * @param policyChain
168      * @return
169      * @throws BuilderException
170      * @throws UnsupportedEncodingException
171      */
172     protected static String formatYaml(ClampProperties refProp, ModelProperties prop, String modelElementId,
173             PolicyChain policyChain) throws BuilderException, UnsupportedEncodingException {
174         // get property objects
175         Global global = prop.getGlobal();
176         prop.setCurrentModelElementId(modelElementId);
177         prop.setPolicyUniqueId(policyChain.getPolicyId());
178         // convert values to SDC objects
179         Service service = new Service(global.getService());
180         Resource[] vfResources = convertToResource(global.getResourceVf(), ResourceType.VF);
181         Resource[] vfcResources = convertToResource(global.getResourceVfc(), ResourceType.VFC);
182         // create builder
183         ControlLoopPolicyBuilder builder = ControlLoopPolicyBuilder.Factory.buildControlLoop(prop.getControlName(),
184                 policyChain.getTimeout(), service, vfResources);
185         builder.addResource(vfcResources);
186         // process each policy
187         Map<String, Policy> policyObjMap = new HashMap<>();
188         List<PolicyItem> policyItemList = orderParentFirst(policyChain.getPolicyItems());
189         for (PolicyItem policyItem : policyItemList) {
190             String policyName = policyItem.getRecipe() + " Policy";
191             Target target = new Target();
192             target.setType(TargetType.VM);
193             // We can send target type as VM/VNF for most of recipes
194             if (policyItem.getRecipeLevel() != null && !policyItem.getRecipeLevel().isEmpty()) {
195                 target.setType(TargetType.valueOf(policyItem.getRecipeLevel()));
196             }
197             target.setResourceID(policyItem.getTargetResourceId());
198             String actor = refProp.getStringValue("op.policy.appc");
199             Map<String, String> payloadMap = null;
200             if ("health-diagnostic".equalsIgnoreCase(policyItem.getRecipe())) {
201                 actor = refProp.getStringValue("op.policy.sdno");
202                 payloadMap = new HashMap<String, String>();
203                 payloadMap.put("ttl", policyItem.getRecipePayload());
204             }
205             // For reboot recipe we have to send type as SOFT/HARD in pay load
206             if (policyItem.getRecipeInfo() != null && !policyItem.getRecipeInfo().isEmpty()) {
207                 payloadMap = new HashMap<String, String>();
208                 payloadMap.put("type", policyItem.getRecipeInfo());
209             }
210             Policy policyObj;
211             if (policyItemList.indexOf(policyItem) == 0) {
212                 String policyDescription = policyItem.getRecipe()
213                         + " Policy - the trigger (no parent) policy - created by CLDS";
214                 policyObj = builder.setTriggerPolicy(policyName, policyDescription, actor, target,
215                         policyItem.getRecipe(), payloadMap, policyItem.getMaxRetries(), policyItem.getRetryTimeLimit());
216             } else {
217                 Policy parentPolicyObj = policyObjMap.get(policyItem.getParentPolicy());
218                 String policyDescription = policyItem.getRecipe() + " Policy - triggered conditionally by "
219                         + parentPolicyObj.getName() + " - created by CLDS";
220                 policyObj = builder.setPolicyForPolicyResult(policyName, policyDescription, actor, target,
221                         policyItem.getRecipe(), payloadMap, policyItem.getMaxRetries(), policyItem.getRetryTimeLimit(),
222                         parentPolicyObj.getId(), convertToPolicyResult(policyItem.getParentPolicyConditions()));
223                 logger.info("policyObj.id=" + policyObj.getId() + "; parentPolicyObj.id=" + parentPolicyObj.getId());
224             }
225             policyObjMap.put(policyItem.getId(), policyObj);
226         }
227         // Build the specification
228         Results results = builder.buildSpecification();
229         validate(results);
230         return URLEncoder.encode(results.getSpecification(), "UTF-8");
231     }
232
233     protected static void validate(Results results) {
234         if (results.isValid()) {
235             logger.info("results.getSpecification()=" + results.getSpecification());
236         } else {
237             // throw exception with error info
238             StringBuilder sb = new StringBuilder();
239             sb.append("Operation Policy validation problem: ControlLoopPolicyBuilder failed with following messages: ");
240             for (Message message : results.getMessages()) {
241                 sb.append(message.getMessage());
242                 sb.append("; ");
243             }
244             throw new BadRequestException(sb.toString());
245         }
246     }
247
248     /**
249      * Order list of PolicyItems so that parents come before any of their
250      * children
251      *
252      * @param inOrigList
253      * @return
254      */
255     private static List<PolicyItem> orderParentFirst(List<PolicyItem> inOrigList) {
256         List<PolicyItem> inList = new ArrayList<>();
257         inList.addAll(inOrigList);
258         List<PolicyItem> outList = new ArrayList<>();
259         int prevSize = 0;
260         while (!inList.isEmpty()) {
261             // check if there's a loop in the policy chain (the inList should
262             // have been reduced by at least one)
263             if (inList.size() == prevSize) {
264                 throw new BadRequestException("Operation Policy validation problem: loop in Operation Policy chain");
265             }
266             prevSize = inList.size();
267             // the following loop should remove at least one PolicyItem from the
268             // inList
269             Iterator<PolicyItem> inListItr = inList.iterator();
270             while (inListItr.hasNext()) {
271                 PolicyItem inItem = inListItr.next();
272                 // check for trigger policy (no parent)
273                 String parent = inItem.getParentPolicy();
274                 if (parent == null || parent.length() == 0) {
275                     if (!outList.isEmpty()) {
276                         throw new BadRequestException(
277                                 "Operation Policy validation problem: more than one trigger policy");
278                     } else {
279                         outList.add(inItem);
280                         inListItr.remove();
281                     }
282                 } else {
283                     // check if this PolicyItem's parent has been processed
284                     for (PolicyItem outItem : outList) {
285                         if (outItem.getId().equals(parent)) {
286                             // if the inItem parent is already in the outList,
287                             // then add inItem to outList and remove from inList
288                             outList.add(inItem);
289                             inListItr.remove();
290                             break;
291                         }
292                     }
293                 }
294             }
295         }
296         return outList;
297     }
298
299     /**
300      * Convert a List of resource strings to an array of Resource objects.
301      *
302      * @param stringList
303      * @param resourceType
304      * @return
305      */
306     protected static Resource[] convertToResource(List<String> stringList, ResourceType resourceType) {
307         if (stringList == null || stringList.isEmpty()) {
308             return new Resource[0];
309         }
310         return stringList.stream().map(stringElem -> new Resource(stringElem, resourceType)).toArray(Resource[]::new);
311     }
312
313     /**
314      * Convert a List of policy result strings to an array of PolicyResult
315      * objects.
316      *
317      * @param prList
318      * @return
319      */
320     protected static PolicyResult[] convertToPolicyResult(List<String> prList) {
321         if (prList == null || prList.isEmpty()) {
322             return new PolicyResult[0];
323         }
324         return prList.stream().map(PolicyResult::toResult).toArray(PolicyResult[]::new);
325     }
326 }