2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 Nordix Foundation.
4 * ================================================================================
5 * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.policy.clamp.controlloop.runtime.supervision;
25 import java.util.HashMap;
26 import java.util.List;
28 import org.apache.commons.lang3.tuple.Pair;
29 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
30 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
31 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
32 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
33 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus;
34 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantUtils;
35 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
36 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider;
37 import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
38 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopStateChangePublisher;
39 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopUpdatePublisher;
40 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusReqPublisher;
41 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantUpdatePublisher;
42 import org.onap.policy.models.base.PfModelException;
43 import org.onap.policy.models.provider.PolicyModelsProvider;
44 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import org.springframework.stereotype.Component;
52 * This class is used to scan the control loops in the database and check if they are in the correct state.
55 public class SupervisionScanner {
56 private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class);
58 private final HandleCounter<ToscaConceptIdentifier> controlLoopCounter = new HandleCounter<>();
59 private final HandleCounter<ToscaConceptIdentifier> participantStatusCounter = new HandleCounter<>();
60 private final HandleCounter<Pair<ToscaConceptIdentifier, ToscaConceptIdentifier>> participantUpdateCounter =
61 new HandleCounter<>();
63 private final Map<ToscaConceptIdentifier, Integer> phaseMap = new HashMap<>();
65 private final ControlLoopProvider controlLoopProvider;
66 private final PolicyModelsProvider modelsProvider;
67 private final ControlLoopStateChangePublisher controlLoopStateChangePublisher;
68 private final ControlLoopUpdatePublisher controlLoopUpdatePublisher;
69 private final ParticipantProvider participantProvider;
70 private final ParticipantStatusReqPublisher participantStatusReqPublisher;
71 private final ParticipantUpdatePublisher participantUpdatePublisher;
74 * Constructor for instantiating SupervisionScanner.
76 * @param controlLoopProvider the provider to use to read control loops from the database
77 * @param modelsProvider the Policy Models Provider
78 * @param controlLoopStateChangePublisher the ControlLoop StateChange Publisher
79 * @param controlLoopUpdatePublisher the ControlLoopUpdate Publisher
80 * @param participantProvider the Participant Provider
81 * @param participantStatusReqPublisher the Participant StatusReq Publisher
82 * @param participantUpdatePublisher the Participant Update Publisher
83 * @param clRuntimeParameterGroup the parameters for the control loop runtime
85 public SupervisionScanner(final ControlLoopProvider controlLoopProvider, PolicyModelsProvider modelsProvider,
86 final ControlLoopStateChangePublisher controlLoopStateChangePublisher,
87 ControlLoopUpdatePublisher controlLoopUpdatePublisher, ParticipantProvider participantProvider,
88 ParticipantStatusReqPublisher participantStatusReqPublisher,
89 ParticipantUpdatePublisher participantUpdatePublisher,
90 final ClRuntimeParameterGroup clRuntimeParameterGroup) {
91 this.controlLoopProvider = controlLoopProvider;
92 this.modelsProvider = modelsProvider;
93 this.controlLoopStateChangePublisher = controlLoopStateChangePublisher;
94 this.controlLoopUpdatePublisher = controlLoopUpdatePublisher;
95 this.participantProvider = participantProvider;
96 this.participantStatusReqPublisher = participantStatusReqPublisher;
97 this.participantUpdatePublisher = participantUpdatePublisher;
99 controlLoopCounter.setMaxRetryCount(
100 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
101 controlLoopCounter.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
103 participantUpdateCounter.setMaxRetryCount(
104 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
105 participantUpdateCounter
106 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
108 participantStatusCounter.setMaxRetryCount(
109 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
110 participantStatusCounter.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
116 * @param counterCheck if true activate counter and retry
118 public void run(boolean counterCheck) {
119 LOGGER.debug("Scanning control loops in the database . . .");
123 for (Participant participant : participantProvider.getParticipants(null, null)) {
124 scanParticipantStatus(participant);
126 } catch (PfModelException pfme) {
127 LOGGER.warn("error reading participant from database", pfme);
133 var list = modelsProvider.getServiceTemplateList(null, null);
134 if (list != null && !list.isEmpty()) {
135 ToscaServiceTemplate toscaServiceTemplate = list.get(0);
137 for (ControlLoop controlLoop : controlLoopProvider.getControlLoops(null, null)) {
138 scanControlLoop(controlLoop, toscaServiceTemplate, counterCheck);
141 } catch (PfModelException pfme) {
142 LOGGER.warn("error reading control loops from database", pfme);
146 scanParticipantUpdate();
149 LOGGER.debug("Control loop scan complete . . .");
152 private void scanParticipantUpdate() {
153 LOGGER.debug("Scanning participants to update . . .");
155 for (var id : participantUpdateCounter.keySet()) {
156 if (participantUpdateCounter.isFault(id)) {
157 LOGGER.debug("report Participant Update fault");
159 } else if (participantUpdateCounter.getDuration(id) > participantUpdateCounter.getMaxWaitMs()) {
161 if (participantUpdateCounter.count(id)) {
162 LOGGER.debug("retry message ParticipantUpdate");
163 participantUpdatePublisher.send(null, true);
165 LOGGER.debug("report Participant Update fault");
166 participantUpdateCounter.setFault(id);
171 LOGGER.debug("Participants to update scan complete . . .");
174 private void scanParticipantStatus(Participant participant) throws PfModelException {
175 ToscaConceptIdentifier id = participant.getKey().asIdentifier();
176 if (participantStatusCounter.isFault(id)) {
177 LOGGER.debug("report Participant fault");
180 if (participantStatusCounter.getDuration(id) > participantStatusCounter.getMaxWaitMs()) {
181 if (participantStatusCounter.count(id)) {
182 LOGGER.debug("retry message ParticipantStatusReq");
183 participantStatusReqPublisher.send(id);
184 participant.setHealthStatus(ParticipantHealthStatus.NOT_HEALTHY);
186 LOGGER.debug("report Participant fault");
187 participantStatusCounter.setFault(id);
188 participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
190 participantProvider.updateParticipants(List.of(participant));
195 * handle participant Status message.
197 public void handleParticipantStatus(ToscaConceptIdentifier id) {
198 participantStatusCounter.clear(id);
201 public void handleParticipantRegister(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
202 participantUpdateCounter.clear(id);
205 public void handleParticipantUpdateAck(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
206 participantUpdateCounter.remove(id);
209 private void scanControlLoop(final ControlLoop controlLoop, ToscaServiceTemplate toscaServiceTemplate,
210 boolean counterCheck) throws PfModelException {
211 LOGGER.debug("scanning control loop {} . . .", controlLoop.getKey().asIdentifier());
213 if (controlLoop.getState().equals(controlLoop.getOrderedState().asState())) {
214 LOGGER.debug("control loop {} scanned, OK", controlLoop.getKey().asIdentifier());
216 // Clear missed report counter on Control Loop
217 clearFaultAndCounter(controlLoop);
221 var completed = true;
222 var minSpNotCompleted = 1000; // min startPhase not completed
223 for (ControlLoopElement element : controlLoop.getElements().values()) {
224 if (!element.getState().equals(element.getOrderedState().asState())) {
226 ToscaNodeTemplate toscaNodeTemplate = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates()
227 .get(element.getDefinition().getName());
228 int startPhase = ParticipantUtils.findStartPhase(toscaNodeTemplate.getProperties());
229 minSpNotCompleted = Math.min(minSpNotCompleted, startPhase);
234 LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
235 controlLoop.getOrderedState());
237 controlLoop.setState(controlLoop.getOrderedState().asState());
238 controlLoopProvider.updateControlLoop(controlLoop);
240 // Clear missed report counter on Control Loop
241 clearFaultAndCounter(controlLoop);
243 LOGGER.debug("control loop scan: transition from state {} to {} not completed", controlLoop.getState(),
244 controlLoop.getOrderedState());
246 if (minSpNotCompleted != phaseMap.getOrDefault(controlLoop.getKey().asIdentifier(), 0)
247 && ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
248 phaseMap.put(controlLoop.getKey().asIdentifier(), minSpNotCompleted);
249 sendControlLoopMsg(controlLoop, minSpNotCompleted);
250 } else if (counterCheck) {
251 handleCounter(controlLoop, minSpNotCompleted);
256 private void clearFaultAndCounter(ControlLoop controlLoop) {
257 controlLoopCounter.clear(controlLoop.getKey().asIdentifier());
261 private void handleCounter(ControlLoop controlLoop, int startPhase) {
262 ToscaConceptIdentifier id = controlLoop.getKey().asIdentifier();
263 if (controlLoopCounter.isFault(id)) {
264 LOGGER.debug("report ControlLoop fault");
268 if (controlLoopCounter.getDuration(id) > controlLoopCounter.getMaxWaitMs()) {
269 if (controlLoopCounter.count(id)) {
270 phaseMap.put(id, startPhase);
271 sendControlLoopMsg(controlLoop, startPhase);
273 LOGGER.debug("report ControlLoop fault");
274 controlLoopCounter.setFault(id);
279 private void sendControlLoopMsg(ControlLoop controlLoop, int startPhase) {
280 if (ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
281 LOGGER.debug("retry message ControlLoopUpdate");
282 controlLoopUpdatePublisher.send(controlLoop, startPhase);
284 LOGGER.debug("retry message ControlLoopStateChange");
285 controlLoopStateChangePublisher.send(controlLoop);