9fe3c94cea46c9f3030e074b1f8f921d02db57f8
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019-2021 Nordix Foundation.
4  *  Modifications Copyright (C) 2020-2021 Bell Canada. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.services.onappf.handler;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.LinkedHashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.stream.Collectors;
34 import org.onap.policy.apex.core.engine.EngineParameters;
35 import org.onap.policy.apex.core.engine.TaskParameters;
36 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
37 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
38 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInfo;
39 import org.onap.policy.apex.model.basicmodel.concepts.AxKeyInformation;
40 import org.onap.policy.apex.model.basicmodel.service.ModelService;
41 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbum;
42 import org.onap.policy.apex.model.contextmodel.concepts.AxContextAlbums;
43 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchema;
44 import org.onap.policy.apex.model.contextmodel.concepts.AxContextSchemas;
45 import org.onap.policy.apex.model.enginemodel.concepts.AxEngineModel;
46 import org.onap.policy.apex.model.eventmodel.concepts.AxEvent;
47 import org.onap.policy.apex.model.eventmodel.concepts.AxEvents;
48 import org.onap.policy.apex.model.policymodel.concepts.AxPolicies;
49 import org.onap.policy.apex.model.policymodel.concepts.AxPolicy;
50 import org.onap.policy.apex.model.policymodel.concepts.AxPolicyModel;
51 import org.onap.policy.apex.model.policymodel.concepts.AxTask;
52 import org.onap.policy.apex.model.policymodel.concepts.AxTasks;
53 import org.onap.policy.apex.service.engine.main.ApexMain;
54 import org.onap.policy.apex.service.parameters.ApexParameterConstants;
55 import org.onap.policy.apex.service.parameters.ApexParameters;
56 import org.onap.policy.apex.services.onappf.exception.ApexStarterException;
57 import org.onap.policy.common.parameters.ParameterService;
58 import org.onap.policy.common.utils.coder.CoderException;
59 import org.onap.policy.common.utils.coder.StandardCoder;
60 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
61 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
62 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
63 import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 /**
68  * This class instantiates the Apex Engine based on instruction from PAP.
69  *
70  * @author Ajith Sreekumar (ajith.sreekumar@est.tech)
71  */
72 public class ApexEngineHandler {
73
74     private static final Logger LOGGER = LoggerFactory.getLogger(ApexEngineHandler.class);
75
76     private Map<ToscaConceptIdentifier, ApexMain> apexMainMap = new LinkedHashMap<>();
77
78     /**
79      * Constructs the object. Extracts the config and model files from each policy and instantiates the apex engine.
80      *
81      * @param policies the list of policies
82      * @throws ApexStarterException if the apex engine instantiation failed using the policies passed
83      */
84     public ApexEngineHandler(List<ToscaPolicy> policies) throws ApexStarterException {
85         LOGGER.debug("Starting apex engine.");
86         initiateApexEngineForPolicies(policies);
87     }
88
89     /**
90      * Updates the Apex Engine with the policy model created from new list of policies.
91      *
92      * @param policies the list of policies
93      * @throws ApexStarterException if the apex engine instantiation failed using the policies passed
94      */
95     public void updateApexEngine(List<ToscaPolicy> policies) throws ApexStarterException {
96         List<ToscaConceptIdentifier> runningPolicies = getRunningPolicies();
97         List<ToscaPolicy> policiesToDeploy = policies.stream()
98             .filter(policy -> !runningPolicies.contains(policy.getIdentifier())).collect(Collectors.toList());
99         List<ToscaConceptIdentifier> policiesToUnDeploy = runningPolicies.stream()
100             .filter(polId -> policies.stream().noneMatch(policy -> policy.getIdentifier().equals(polId)))
101             .collect(Collectors.toList());
102         Map<ToscaConceptIdentifier, ApexMain> undeployedPoliciesMainMap = new LinkedHashMap<>();
103         policiesToUnDeploy.forEach(policyId -> {
104             ApexMain apexMain = apexMainMap.get(policyId);
105             try {
106                 apexMain.shutdown();
107                 undeployedPoliciesMainMap.put(policyId, apexMain);
108                 apexMainMap.remove(policyId);
109             } catch (ApexException e) {
110                 LOGGER.error("Shutting down policy {} failed", policyId, e);
111             }
112         });
113         if (!undeployedPoliciesMainMap.isEmpty()) {
114             updateModelAndParameterServices(undeployedPoliciesMainMap);
115         }
116         if (!policiesToDeploy.isEmpty()) {
117             initiateApexEngineForPolicies(policiesToDeploy);
118         }
119         if (apexMainMap.isEmpty()) {
120             ModelService.clear();
121             ParameterService.clear();
122         }
123     }
124
125     /**
126      * Clear the corresponding items from ModelService and ParameterService.
127      *
128      * @param undeployedPoliciesMainMap the policies that are undeployed
129      */
130     private void updateModelAndParameterServices(Map<ToscaConceptIdentifier, ApexMain> undeployedPoliciesMainMap) {
131         Set<String> inputParamKeysToRetain = new HashSet<>();
132         Set<String> outputParamKeysToRetain = new HashSet<>();
133         List<TaskParameters> taskParametersToRetain = new ArrayList<>();
134         List<String> executorParamKeysToRetain = new ArrayList<>();
135         List<String> schemaParamKeysToRetain = new ArrayList<>();
136
137         Map<AxArtifactKey, AxKeyInfo> keyInfoMapToRetain = new HashMap<>();
138         Map<AxArtifactKey, AxContextSchema> schemaMapToRetain = new HashMap<>();
139         Map<AxArtifactKey, AxEvent> eventMapToRetain = new HashMap<>();
140         Map<AxArtifactKey, AxContextAlbum> albumMapToRetain = new HashMap<>();
141         Map<AxArtifactKey, AxTask> taskMapToRetain = new HashMap<>();
142         Map<AxArtifactKey, AxPolicy> policyMapToRetain = new HashMap<>();
143
144         apexMainMap.values().forEach(main -> {
145             inputParamKeysToRetain.addAll(main.getApexParameters().getEventInputParameters().keySet());
146             outputParamKeysToRetain.addAll(main.getApexParameters().getEventOutputParameters().keySet());
147             taskParametersToRetain.addAll(
148                 main.getApexParameters().getEngineServiceParameters().getEngineParameters().getTaskParameters());
149             executorParamKeysToRetain.addAll(main.getApexParameters().getEngineServiceParameters().getEngineParameters()
150                 .getExecutorParameterMap().keySet());
151             schemaParamKeysToRetain.addAll(main.getApexParameters().getEngineServiceParameters().getEngineParameters()
152                 .getContextParameters().getSchemaParameters().getSchemaHelperParameterMap().keySet());
153
154             AxPolicyModel policyModel = main.getActivator().getPolicyModel();
155             keyInfoMapToRetain.putAll(policyModel.getKeyInformation().getKeyInfoMap());
156             schemaMapToRetain.putAll(policyModel.getSchemas().getSchemasMap());
157             eventMapToRetain.putAll(policyModel.getEvents().getEventMap());
158             albumMapToRetain.putAll(policyModel.getAlbums().getAlbumsMap());
159             taskMapToRetain.putAll(policyModel.getTasks().getTaskMap());
160             policyMapToRetain.putAll(policyModel.getPolicies().getPolicyMap());
161         });
162         for (ApexMain main : undeployedPoliciesMainMap.values()) {
163             handleParametersRemoval(inputParamKeysToRetain, outputParamKeysToRetain, taskParametersToRetain,
164                 executorParamKeysToRetain, schemaParamKeysToRetain, main);
165
166             if (null != main.getActivator() && null != main.getActivator().getPolicyModel()) {
167                 handleAxConceptsRemoval(keyInfoMapToRetain, schemaMapToRetain, eventMapToRetain, albumMapToRetain,
168                     taskMapToRetain, policyMapToRetain, main);
169             }
170         }
171     }
172
173     private void handleParametersRemoval(Set<String> inputParamKeysToRetain, Set<String> outputParamKeysToRetain,
174         List<TaskParameters> taskParametersToRetain, List<String> executorParamKeysToRetain,
175         List<String> schemaParamKeysToRetain, ApexMain main) {
176         ApexParameters existingParameters = ParameterService.get(ApexParameterConstants.MAIN_GROUP_NAME);
177         List<String> eventInputParamKeysToRemove = main.getApexParameters().getEventInputParameters().keySet().stream()
178             .filter(key -> !inputParamKeysToRetain.contains(key)).collect(Collectors.toList());
179         List<String> eventOutputParamKeysToRemove = main.getApexParameters().getEventOutputParameters().keySet()
180             .stream().filter(key -> !outputParamKeysToRetain.contains(key)).collect(Collectors.toList());
181         eventInputParamKeysToRemove.forEach(existingParameters.getEventInputParameters()::remove);
182         eventOutputParamKeysToRemove.forEach(existingParameters.getEventOutputParameters()::remove);
183         EngineParameters engineParameters = main.getApexParameters().getEngineServiceParameters().getEngineParameters();
184         final List<TaskParameters> taskParametersToRemove = engineParameters.getTaskParameters().stream()
185             .filter(taskParameter -> !taskParametersToRetain.contains(taskParameter)).collect(Collectors.toList());
186         final List<String> executorParamKeysToRemove = engineParameters.getExecutorParameterMap().keySet().stream()
187             .filter(key -> !executorParamKeysToRetain.contains(key)).collect(Collectors.toList());
188         final List<String> schemaParamKeysToRemove =
189             engineParameters.getContextParameters().getSchemaParameters().getSchemaHelperParameterMap().keySet()
190                 .stream().filter(key -> !schemaParamKeysToRetain.contains(key)).collect(Collectors.toList());
191         EngineParameters aggregatedEngineParameters =
192             existingParameters.getEngineServiceParameters().getEngineParameters();
193         aggregatedEngineParameters.getTaskParameters().removeAll(taskParametersToRemove);
194         executorParamKeysToRemove.forEach(aggregatedEngineParameters.getExecutorParameterMap()::remove);
195         schemaParamKeysToRemove.forEach(aggregatedEngineParameters.getContextParameters().getSchemaParameters()
196             .getSchemaHelperParameterMap()::remove);
197     }
198
199     private void handleAxConceptsRemoval(Map<AxArtifactKey, AxKeyInfo> keyInfoMapToRetain,
200         Map<AxArtifactKey, AxContextSchema> schemaMapToRetain, Map<AxArtifactKey, AxEvent> eventMapToRetain,
201         Map<AxArtifactKey, AxContextAlbum> albumMapToRetain, Map<AxArtifactKey, AxTask> taskMapToRetain,
202         Map<AxArtifactKey, AxPolicy> policyMapToRetain, ApexMain main) {
203         final AxPolicyModel policyModel = main.getActivator().getPolicyModel();
204         final List<AxArtifactKey> keyInfoKeystoRemove = policyModel.getKeyInformation().getKeyInfoMap().keySet()
205             .stream().filter(key -> !keyInfoMapToRetain.containsKey(key)).collect(Collectors.toList());
206         final List<AxArtifactKey> schemaKeystoRemove = policyModel.getSchemas().getSchemasMap().keySet().stream()
207             .filter(key -> !schemaMapToRetain.containsKey(key)).collect(Collectors.toList());
208         final List<AxArtifactKey> eventKeystoRemove = policyModel.getEvents().getEventMap().keySet().stream()
209             .filter(key -> !eventMapToRetain.containsKey(key)).collect(Collectors.toList());
210         final List<AxArtifactKey> albumKeystoRemove = policyModel.getAlbums().getAlbumsMap().keySet().stream()
211             .filter(key -> !albumMapToRetain.containsKey(key)).collect(Collectors.toList());
212         final List<AxArtifactKey> taskKeystoRemove = policyModel.getTasks().getTaskMap().keySet().stream()
213             .filter(key -> !taskMapToRetain.containsKey(key)).collect(Collectors.toList());
214         final List<AxArtifactKey> policyKeystoRemove = policyModel.getPolicies().getPolicyMap().keySet().stream()
215             .filter(key -> !policyMapToRetain.containsKey(key)).collect(Collectors.toList());
216
217         final Map<AxArtifactKey, AxKeyInfo> keyInfoMap = ModelService.getModel(AxKeyInformation.class).getKeyInfoMap();
218         final Map<AxArtifactKey, AxContextSchema> schemasMap =
219             ModelService.getModel(AxContextSchemas.class).getSchemasMap();
220         final Map<AxArtifactKey, AxEvent> eventMap = ModelService.getModel(AxEvents.class).getEventMap();
221         final Map<AxArtifactKey, AxContextAlbum> albumsMap =
222             ModelService.getModel(AxContextAlbums.class).getAlbumsMap();
223         final Map<AxArtifactKey, AxTask> taskMap = ModelService.getModel(AxTasks.class).getTaskMap();
224         final Map<AxArtifactKey, AxPolicy> policyMap = ModelService.getModel(AxPolicies.class).getPolicyMap();
225
226         // replace the ModelService with the right concept definition
227         // this can get corrupted in case of deploying policies with duplicate concept keys
228         keyInfoMap.putAll(keyInfoMapToRetain);
229         schemasMap.putAll(schemaMapToRetain);
230         eventMap.putAll(eventMapToRetain);
231         albumsMap.putAll(albumMapToRetain);
232         taskMap.putAll(taskMapToRetain);
233         policyMap.putAll(policyMapToRetain);
234
235         keyInfoKeystoRemove.forEach(keyInfoMap::remove);
236         schemaKeystoRemove.forEach(schemasMap::remove);
237         eventKeystoRemove.forEach(eventMap::remove);
238         albumKeystoRemove.forEach(albumsMap::remove);
239         taskKeystoRemove.forEach(taskMap::remove);
240         policyKeystoRemove.forEach(policyMap::remove);
241     }
242
243     private void initiateApexEngineForPolicies(List<ToscaPolicy> policies)
244         throws ApexStarterException {
245         Map<ToscaConceptIdentifier, ApexMain> failedPoliciesMainMap = new LinkedHashMap<>();
246         for (ToscaPolicy policy : policies) {
247             String policyName = policy.getIdentifier().getName();
248             final StandardCoder standardCoder = new StandardCoder();
249             ToscaServiceTemplate toscaServiceTemplate = new ToscaServiceTemplate();
250             ToscaTopologyTemplate toscaTopologyTemplate = new ToscaTopologyTemplate();
251             toscaTopologyTemplate.setPolicies(List.of(Map.of(policyName, policy)));
252             toscaServiceTemplate.setToscaTopologyTemplate(toscaTopologyTemplate);
253             File file;
254             try {
255                 file = File.createTempFile(policyName, ".json");
256                 standardCoder.encode(file, toscaServiceTemplate);
257             } catch (CoderException | IOException e) {
258                 throw new ApexStarterException(e);
259             }
260             final String[] apexArgs = {"-p", file.getAbsolutePath()};
261             LOGGER.info("Starting apex engine for policy {}", policy.getIdentifier());
262             ApexMain apexMain = new ApexMain(apexArgs);
263             if (apexMain.isAlive()) {
264                 apexMainMap.put(policy.getIdentifier(), apexMain);
265             } else {
266                 failedPoliciesMainMap.put(policy.getIdentifier(), apexMain);
267                 LOGGER.error("Execution of policy {} failed", policy.getIdentifier());
268             }
269         }
270         if (apexMainMap.isEmpty()) {
271             ModelService.clear();
272             ParameterService.clear();
273             throw new ApexStarterException("Apex Engine failed to start.");
274         } else if (failedPoliciesMainMap.size() > 0) {
275             updateModelAndParameterServices(failedPoliciesMainMap);
276             if (failedPoliciesMainMap.size() == policies.size()) {
277                 throw new ApexStarterException("Updating the APEX engine with new policies failed.");
278             }
279         }
280     }
281
282     /**
283      * Method to get the APEX engine statistics.
284      */
285     public List<AxEngineModel> getEngineStats() {
286         // engineStats from all the apexMain instances running individual tosca policies are combined here.
287         return apexMainMap.values().stream().filter(apexMain -> (null != apexMain && apexMain.isAlive()))
288             .flatMap(m -> m.getEngineStats().stream()).collect(Collectors.toList());
289     }
290
291     /**
292      * Method to check whether the apex engine is running or not.
293      */
294     public boolean isApexEngineRunning() {
295         return apexMainMap.values().stream().anyMatch(apexMain -> (null != apexMain && apexMain.isAlive()));
296     }
297
298     /**
299      * Method that return the list of running policies in the apex engine.
300      */
301     public List<ToscaConceptIdentifier> getRunningPolicies() {
302         return new ArrayList<>(apexMainMap.keySet());
303     }
304
305     /**
306      * Method to shut down the apex engine.
307      */
308     public void shutdown() throws ApexStarterException {
309         try {
310             LOGGER.debug("Shutting down apex engine.");
311             for (ApexMain apexMain : apexMainMap.values()) {
312                 apexMain.shutdown();
313             }
314             apexMainMap.clear();
315             ModelService.clear();
316             ParameterService.clear();
317         } catch (final ApexException e) {
318             throw new ApexStarterException(e);
319         }
320     }
321 }