Merge "Fix log reporting"
[clamp.git] / src / main / java / org / onap / clamp / loop / LoopOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2019 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.loop;
25
26 import com.att.eelf.configuration.EELFLogger;
27 import com.att.eelf.configuration.EELFManager;
28 import com.google.gson.JsonArray;
29 import com.google.gson.JsonElement;
30 import com.google.gson.JsonNull;
31 import com.google.gson.JsonObject;
32 import com.google.gson.JsonPrimitive;
33
34 import java.io.IOException;
35 import java.lang.reflect.Array;
36 import java.util.Collection;
37 import java.util.Iterator;
38 import java.util.Map;
39 import java.util.Set;
40
41 import org.apache.camel.Exchange;
42 import org.apache.camel.Message;
43 import org.json.simple.JSONObject;
44 import org.json.simple.parser.JSONParser;
45 import org.json.simple.parser.ParseException;
46 import org.onap.clamp.clds.config.ClampProperties;
47 import org.onap.clamp.policy.operational.OperationalPolicy;
48 import org.springframework.beans.factory.annotation.Autowired;
49 import org.springframework.stereotype.Component;
50 import org.yaml.snakeyaml.Yaml;
51
52 /**
53  * Closed loop operations.
54  */
55 @Component
56 public class LoopOperation {
57
58     protected static final EELFLogger logger = EELFManager.getInstance().getLogger(LoopOperation.class);
59     protected static final EELFLogger auditLogger = EELFManager.getInstance().getMetricsLogger();
60     private static final String DCAE_LINK_FIELD = "links";
61     private static final String DCAE_STATUS_FIELD = "status";
62     private static final String DCAE_DEPLOYMENT_TEMPLATE = "dcae.deployment.template";
63     private static final String DCAE_SERVICETYPE_ID = "serviceTypeId";
64     private static final String DCAE_INPUTS = "inputs";
65     private static final String DCAE_DEPLOYMENT_PREFIX = "closedLoop_";
66     private static final String DCAE_DEPLOYMENT_SUFIX = "_deploymentId";
67     private final LoopService loopService;
68     private final ClampProperties refProp;
69
70     public enum TempLoopState {
71         NOT_SUBMITTED, SUBMITTED, DEPLOYED, NOT_DEPLOYED, PROCESSING, IN_ERROR;
72     }
73
74     /**
75      * The constructor.
76      * @param loopService The loop service
77      * @param refProp The clamp properties
78      */
79     @Autowired
80     public LoopOperation(LoopService loopService, ClampProperties refProp) {
81         this.loopService = loopService;
82         this.refProp = refProp;
83     }
84
85     /**
86      * Get the payload used to send the deploy closed loop request.
87      *
88      * @param loop The loop
89      * @return The payload used to send deploy closed loop request
90      * @throws IOException IOException
91      */
92     public String getDeployPayload(Loop loop) throws IOException {
93         Yaml yaml = new Yaml();
94         Map<String, Object> yamlMap = yaml.load(loop.getBlueprint());
95         JsonObject bluePrint = wrapSnakeObject(yamlMap).getAsJsonObject();
96
97         String serviceTypeId = loop.getDcaeBlueprintId();
98
99         JsonObject rootObject = refProp.getJsonTemplate(DCAE_DEPLOYMENT_TEMPLATE).getAsJsonObject();
100         rootObject.addProperty(DCAE_SERVICETYPE_ID, serviceTypeId);
101         if (bluePrint != null) {
102             rootObject.add(DCAE_INPUTS, bluePrint);
103         }
104         String apiBodyString = rootObject.toString();
105         logger.info("Dcae api Body String - " + apiBodyString);
106
107         return apiBodyString;
108     }
109
110     /**
111      * Get the deployment id.
112      *
113      * @param loop The loop
114      * @return The deployment id
115      * @throws IOException IOException
116      */
117     public String getDeploymentId(Loop loop) {
118         // Set the deploymentId if not present yet
119         String deploymentId = "";
120         // If model is already deployed then pass same deployment id
121         if (loop.getDcaeDeploymentId() != null && !loop.getDcaeDeploymentId().isEmpty()) {
122             deploymentId = loop.getDcaeDeploymentId();
123         } else {
124             deploymentId = DCAE_DEPLOYMENT_PREFIX + loop.getName() + DCAE_DEPLOYMENT_SUFIX;
125         }
126         return deploymentId;
127     }
128
129     /**
130      * Update the loop info.
131      *
132      * @param camelExchange The camel exchange
133      * @param loop The loop
134      * @param deploymentId The deployment id
135      * @throws ParseException The parse exception
136      */
137     public void updateLoopInfo(Exchange camelExchange, Loop loop, String deploymentId) throws ParseException {
138         Message in = camelExchange.getIn();
139         String msg = in.getBody(String.class);
140
141         JSONParser parser = new JSONParser();
142         Object obj0 = parser.parse(msg);
143         JSONObject jsonObj = (JSONObject) obj0;
144
145         JSONObject linksObj = (JSONObject) jsonObj.get(DCAE_LINK_FIELD);
146         String statusUrl = (String) linksObj.get(DCAE_STATUS_FIELD);
147
148         // use http4 instead of http, because camel http4 component is used to do the http call
149         String newStatusUrl = statusUrl.replaceAll("http:", "http4:");
150
151         loop.setDcaeDeploymentId(deploymentId);
152         loop.setDcaeDeploymentStatusUrl(newStatusUrl);
153         loopService.saveOrUpdateLoop(loop);
154     }
155
156     /**
157      * Get the Closed Loop status based on the reply from Policy.
158      *
159      * @param statusCode The status code
160      * @return The state based on policy response
161      * @throws ParseException The parse exception
162      */
163     public String analysePolicyResponse(int statusCode) {
164         if (statusCode == 200) {
165             return TempLoopState.SUBMITTED.toString();
166         } else if (statusCode == 404) {
167             return TempLoopState.NOT_SUBMITTED.toString();
168         }
169         return TempLoopState.IN_ERROR.toString();
170     }
171
172     /**
173      * Get the name of the first Operational policy.
174      *
175      * @param loop The closed loop
176      * @return The name of the first operational policy
177      */
178     public String getOperationalPolicyName(Loop loop) {
179         Set<OperationalPolicy> opSet = (Set<OperationalPolicy>)loop.getOperationalPolicies();
180         Iterator<OperationalPolicy> iterator = opSet.iterator();
181         while (iterator.hasNext()) {
182             OperationalPolicy policy = iterator.next();
183             return policy.getName();
184         }
185         return null;
186     }
187
188     /**
189      * Get the Closed Loop status based on the reply from DCAE.
190      *
191      * @param camelExchange The camel exchange
192      * @return The state based on DCAE response
193      * @throws ParseException The parse exception
194      */
195     public String analyseDcaeResponse(Exchange camelExchange, Integer statusCode) throws ParseException {
196         if (statusCode == null) {
197             return TempLoopState.NOT_DEPLOYED.toString();
198         }
199         if (statusCode == 200) {
200             Message in = camelExchange.getIn();
201             String msg = in.getBody(String.class);
202
203             JSONParser parser = new JSONParser();
204             Object obj0 = parser.parse(msg);
205             JSONObject jsonObj = (JSONObject) obj0;
206
207             String opType = (String) jsonObj.get("operationType");
208             String status = (String) jsonObj.get("status");
209
210             // status = processing/successded/failed
211             if (status.equals("succeeded")) {
212                 if (opType.equals("install")) {
213                     return TempLoopState.DEPLOYED.toString();
214                 } else if (opType.equals("uninstall")) {
215                     return TempLoopState.NOT_DEPLOYED.toString();
216                 }
217             } else if (status.equals("processing")) {
218                 return TempLoopState.PROCESSING.toString();
219             }
220         } else if (statusCode == 404) {
221             return TempLoopState.NOT_DEPLOYED.toString();
222         }
223         return TempLoopState.IN_ERROR.toString();
224     }
225
226     /**
227      * Update the status of the closed loop based on the response from Policy and DCAE.
228      *
229      * @param loop The closed loop
230      * @param policyState The state get from Policy
231      * @param dcaeState The state get from DCAE
232      * @throws ParseException The parse exception
233      */
234     public LoopState updateLoopStatus(Loop loop, TempLoopState policyState, TempLoopState dcaeState) {
235         LoopState clState = LoopState.IN_ERROR;
236         if (policyState == TempLoopState.SUBMITTED) {
237             if (dcaeState == TempLoopState.DEPLOYED) {
238                 clState = LoopState.DEPLOYED;
239             } else if (dcaeState == TempLoopState.PROCESSING) {
240                 clState = LoopState.WAITING;
241             } else if (dcaeState == TempLoopState.NOT_DEPLOYED) {
242                 clState = LoopState.SUBMITTED;
243             }
244         } else if (policyState == TempLoopState.NOT_SUBMITTED) {
245             if (dcaeState == TempLoopState.NOT_DEPLOYED) {
246                 clState = LoopState.DESIGN;
247             }
248         }
249         loop.setLastComputedState(clState);
250         loopService.saveOrUpdateLoop(loop);
251         return clState;
252     }
253
254     private JsonElement wrapSnakeObject(Object obj) {
255         // NULL => JsonNull
256         if (obj == null) {
257             return JsonNull.INSTANCE;
258         }
259
260         // Collection => JsonArray
261         if (obj instanceof Collection) {
262             JsonArray array = new JsonArray();
263             for (Object childObj : (Collection<?>) obj) {
264                 array.add(wrapSnakeObject(childObj));
265             }
266             return array;
267         }
268
269         // Array => JsonArray
270         if (obj.getClass().isArray()) {
271             JsonArray array = new JsonArray();
272
273             int length = Array.getLength(array);
274             for (int i = 0; i < length; i++) {
275                 array.add(wrapSnakeObject(Array.get(array, i)));
276             }
277             return array;
278         }
279
280         // Map => JsonObject
281         if (obj instanceof Map) {
282             Map<?, ?> map = (Map<?, ?>) obj;
283
284             JsonObject jsonObject = new JsonObject();
285             for (final Map.Entry<?, ?> entry : map.entrySet()) {
286                 final String name = String.valueOf(entry.getKey());
287                 final Object value = entry.getValue();
288                 jsonObject.add(name, wrapSnakeObject(value));
289             }
290             return jsonObject;
291         }
292
293         // otherwise take it as a string
294         return new JsonPrimitive(String.valueOf(obj));
295     }
296
297 }