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