8dc49eefbb40894452cf8fca31ab4e0ac206dcfe
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019-2021 Nordix Foundation.
4  *  Modifications Copyright (C) 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.util.Collections;
25 import java.util.HashSet;
26 import java.util.List;
27 import org.onap.policy.apex.service.engine.main.ApexPolicyStatisticsManager;
28 import org.onap.policy.apex.services.onappf.ApexStarterConstants;
29 import org.onap.policy.apex.services.onappf.comm.PdpStatusPublisher;
30 import org.onap.policy.apex.services.onappf.exception.ApexStarterException;
31 import org.onap.policy.common.endpoints.event.comm.TopicSink;
32 import org.onap.policy.common.utils.services.Registry;
33 import org.onap.policy.models.pdp.concepts.PdpResponseDetails;
34 import org.onap.policy.models.pdp.concepts.PdpStatus;
35 import org.onap.policy.models.pdp.concepts.PdpUpdate;
36 import org.onap.policy.models.pdp.enums.PdpResponseStatus;
37 import org.onap.policy.models.pdp.enums.PdpState;
38 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * This class supports the handling of pdp update messages.
44  *
45  * @author Ajith Sreekumar (ajith.sreekumar@est.tech)
46  */
47 public class PdpUpdateMessageHandler {
48
49     private static final Logger LOGGER = LoggerFactory.getLogger(PdpUpdateMessageHandler.class);
50
51     /**
52      * Method which handles a pdp update event from PAP.
53      *
54      * @param pdpUpdateMsg pdp update message
55      */
56     public void handlePdpUpdateEvent(final PdpUpdate pdpUpdateMsg) {
57         final PdpMessageHandler pdpMessageHandler = new PdpMessageHandler();
58         final PdpStatus pdpStatusContext = Registry.get(ApexStarterConstants.REG_PDP_STATUS_OBJECT, PdpStatus.class);
59         PdpResponseDetails pdpResponseDetails = null;
60         if (pdpUpdateMsg.appliesTo(pdpStatusContext.getName(), pdpStatusContext.getPdpGroup(),
61                 pdpStatusContext.getPdpSubgroup())) {
62             if (checkIfAlreadyHandled(pdpUpdateMsg, pdpStatusContext)) {
63                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
64                         PdpResponseStatus.SUCCESS, "Pdp already updated");
65             } else {
66                 pdpResponseDetails = handlePdpUpdate(pdpUpdateMsg, pdpMessageHandler, pdpStatusContext);
67             }
68             final PdpStatusPublisher pdpStatusPublisherTemp =
69                     Registry.get(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER);
70             final PdpStatus pdpStatus = pdpMessageHandler.createPdpStatusFromContext();
71             pdpStatus.setResponse(pdpResponseDetails);
72             pdpStatus.setDescription("Pdp status response message for PdpUpdate");
73             pdpStatusPublisherTemp.send(pdpStatus);
74         }
75     }
76
77     /**
78      * Method to do pdp update.
79      *
80      * @param pdpUpdateMsg the pdp update message
81      * @param pdpMessageHandler the message handler
82      * @param pdpStatusContext the pdp status in memory
83      * @return pdpResponseDetails the pdp response
84      */
85     private PdpResponseDetails handlePdpUpdate(final PdpUpdate pdpUpdateMsg, final PdpMessageHandler pdpMessageHandler,
86         final PdpStatus pdpStatusContext) {
87         PdpResponseDetails pdpResponseDetails = null;
88         final PdpStatusPublisher pdpStatusPublisher = Registry.get(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER);
89         if (null != pdpUpdateMsg.getPdpHeartbeatIntervalMs() && pdpUpdateMsg.getPdpHeartbeatIntervalMs() > 0
90                 && pdpStatusPublisher.getInterval() != pdpUpdateMsg.getPdpHeartbeatIntervalMs()) {
91             updateInterval(pdpUpdateMsg.getPdpHeartbeatIntervalMs());
92         }
93         pdpStatusContext.setPdpGroup(pdpUpdateMsg.getPdpGroup());
94         pdpStatusContext.setPdpSubgroup(pdpUpdateMsg.getPdpSubgroup());
95         pdpStatusContext
96                 .setPolicies(new PdpMessageHandler().getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies()));
97         Registry.registerOrReplace(ApexStarterConstants.REG_APEX_TOSCA_POLICY_LIST, pdpUpdateMsg.getPolicies());
98         if (pdpStatusContext.getState().equals(PdpState.ACTIVE)) {
99             pdpResponseDetails = startOrStopApexEngineBasedOnPolicies(pdpUpdateMsg, pdpMessageHandler);
100
101             ApexEngineHandler apexEngineHandler =
102                 Registry.getOrDefault(ApexStarterConstants.REG_APEX_ENGINE_HANDLER, ApexEngineHandler.class, null);
103             // in hearbeat while in active state, only the policies which are running should be there.
104             // if some policy fails, that shouldn't go in the heartbeat.
105             // If no policies are running, then the policy list in the heartbeat can be empty
106             if (null != apexEngineHandler && apexEngineHandler.isApexEngineRunning()) {
107                 pdpStatusContext.setPolicies(apexEngineHandler.getRunningPolicies());
108             } else {
109                 pdpStatusContext.setPolicies(Collections.emptyList());
110             }
111         }
112         if (null == pdpResponseDetails) {
113             pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
114                     PdpResponseStatus.SUCCESS, "Pdp update successful.");
115         }
116         return pdpResponseDetails;
117     }
118
119     /**
120      * Method to start or stop apex engine based on the list of policies received from pap. When current state is
121      * active, if PAP sends PdpUpdate with empty policies list, stop apex engine, or, if there is a change in policies,
122      * stop the current running policies and the deploy the new ones.
123      *
124      * @param pdpUpdateMsg the pdp update message from pap
125      * @param pdpMessageHandler pdp message handler
126      * @param pdpStatusContext the pdp status object in memory
127      * @return pdpResponseDetails the pdp response
128      */
129     private PdpResponseDetails startOrStopApexEngineBasedOnPolicies(final PdpUpdate pdpUpdateMsg,
130             final PdpMessageHandler pdpMessageHandler) {
131         PdpResponseDetails pdpResponseDetails = null;
132         ApexEngineHandler apexEngineHandler = null;
133         try {
134             apexEngineHandler = Registry.get(ApexStarterConstants.REG_APEX_ENGINE_HANDLER);
135         } catch (final IllegalArgumentException e) {
136             LOGGER.debug("ApenEngineHandler not in registry.", e);
137         }
138         if (pdpUpdateMsg.getPolicies().isEmpty()) {
139             pdpResponseDetails = stopApexEngineBasedOnPolicies(pdpUpdateMsg, pdpMessageHandler, apexEngineHandler);
140         } else {
141             pdpResponseDetails = startApexEngineBasedOnPolicies(pdpUpdateMsg, pdpMessageHandler, apexEngineHandler);
142         }
143         return pdpResponseDetails;
144     }
145
146     private PdpResponseDetails stopApexEngineBasedOnPolicies(final PdpUpdate pdpUpdateMsg,
147         final PdpMessageHandler pdpMessageHandler, ApexEngineHandler apexEngineHandler) {
148         PdpResponseDetails pdpResponseDetails = null;
149         if (null != apexEngineHandler && apexEngineHandler.isApexEngineRunning()) {
150             try {
151                 apexEngineHandler.shutdown();
152                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
153                     PdpResponseStatus.SUCCESS, "Pdp update successful. No policies are running.");
154             } catch (final ApexStarterException e) {
155                 LOGGER.error("Pdp update failed as the policies couldn't be undeployed.", e);
156                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
157                         PdpResponseStatus.FAIL, "Pdp update failed as the policies couldn't be undeployed.");
158             }
159         }
160         return pdpResponseDetails;
161     }
162
163     private PdpResponseDetails startApexEngineBasedOnPolicies(final PdpUpdate pdpUpdateMsg,
164         final PdpMessageHandler pdpMessageHandler, ApexEngineHandler apexEngineHandler) {
165         PdpResponseDetails pdpResponseDetails = null;
166
167         try {
168             if (null != apexEngineHandler && apexEngineHandler.isApexEngineRunning()) {
169                 apexEngineHandler.updateApexEngine(pdpUpdateMsg.getPolicies());
170             } else {
171                 apexEngineHandler = new ApexEngineHandler(pdpUpdateMsg.getPolicies());
172                 Registry.registerOrReplace(ApexStarterConstants.REG_APEX_ENGINE_HANDLER, apexEngineHandler);
173             }
174             if (apexEngineHandler.isApexEngineRunning()) {
175                 List<ToscaConceptIdentifier> runningPolicies = apexEngineHandler.getRunningPolicies();
176                 if (new HashSet<>(runningPolicies)
177                     .equals(new HashSet<>(pdpMessageHandler.getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies())))) {
178                     pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
179                         PdpResponseStatus.SUCCESS, "Apex engine started and policies are running.");
180                 } else {
181                     StringBuilder message =
182                         new StringBuilder("Apex engine started. But, only the following polices are running - ");
183                     for (ToscaConceptIdentifier policy : runningPolicies) {
184                         message.append(policy.getName()).append(":").append(policy.getVersion()).append("  ");
185                     }
186                     message.append(". Other policies failed execution. Please see the logs for more details.");
187                     pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
188                         PdpResponseStatus.SUCCESS, message.toString());
189                 }
190             } else {
191                 pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
192                     PdpResponseStatus.FAIL, "Apex engine failed to start.");
193             }
194         } catch (final ApexStarterException e) {
195             LOGGER.error("Apex engine service running failed. ", e);
196             pdpResponseDetails = pdpMessageHandler.createPdpResonseDetails(pdpUpdateMsg.getRequestId(),
197                     PdpResponseStatus.FAIL, "Apex engine service running failed. " + e.getMessage());
198         }
199         final ApexPolicyStatisticsManager apexPolicyStatisticsManager =
200                 ApexPolicyStatisticsManager.getInstanceFromRegistry();
201         if (apexPolicyStatisticsManager != null) {
202             apexPolicyStatisticsManager
203                     .updatePolicyDeployCounter(pdpResponseDetails.getResponseStatus() == PdpResponseStatus.SUCCESS);
204         }
205         return pdpResponseDetails;
206     }
207
208     /**
209      * Method checks if the Pdp update message is already handled by checking the values in the context.
210      *
211      * @param pdpUpdateMsg pdp update message received from pap
212      * @param pdpStatusContext values saved in context memory
213      * @return boolean flag which tells if the information is same or not
214      */
215     private boolean checkIfAlreadyHandled(final PdpUpdate pdpUpdateMsg, final PdpStatus pdpStatusContext) {
216         return null != pdpStatusContext.getPdpGroup()
217                 && pdpStatusContext.getPdpGroup().equals(pdpUpdateMsg.getPdpGroup())
218                 && null != pdpStatusContext.getPdpSubgroup()
219                 && pdpStatusContext.getPdpSubgroup().equals(pdpUpdateMsg.getPdpSubgroup())
220                 && null != pdpStatusContext.getPolicies() && new PdpMessageHandler()
221                         .getToscaPolicyIdentifiers(pdpUpdateMsg.getPolicies()).equals(pdpStatusContext.getPolicies());
222     }
223
224     /**
225      * Method to update the time interval used by the timer task.
226      *
227      * @param interval time interval received in the pdp update message from pap
228      */
229     public void updateInterval(final long interval) {
230         final PdpStatusPublisher pdpStatusPublisher = Registry.get(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER);
231         pdpStatusPublisher.terminate();
232         final List<TopicSink> topicSinks = Registry.get(ApexStarterConstants.REG_APEX_PDP_TOPIC_SINKS);
233         Registry.registerOrReplace(ApexStarterConstants.REG_PDP_STATUS_PUBLISHER,
234                 new PdpStatusPublisher(topicSinks, interval));
235     }
236 }