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.sendCommissioning(null, null, id.getLeft(), id.getRight());
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 var maxSpNotCompleted = 0; // max startPhase not completed
224 var defaultMin = 1000; // min startPhase
225 var defaultMax = 0; // max startPhase
226 for (ControlLoopElement element : controlLoop.getElements().values()) {
227 ToscaNodeTemplate toscaNodeTemplate = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates()
228 .get(element.getDefinition().getName());
229 int startPhase = ParticipantUtils.findStartPhase(toscaNodeTemplate.getProperties());
230 defaultMin = Math.min(defaultMin, startPhase);
231 defaultMax = Math.max(defaultMax, startPhase);
232 if (!element.getState().equals(element.getOrderedState().asState())) {
234 minSpNotCompleted = Math.min(minSpNotCompleted, startPhase);
235 maxSpNotCompleted = Math.max(maxSpNotCompleted, startPhase);
240 LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
241 controlLoop.getOrderedState());
243 controlLoop.setState(controlLoop.getOrderedState().asState());
244 controlLoopProvider.updateControlLoop(controlLoop);
246 // Clear missed report counter on Control Loop
247 clearFaultAndCounter(controlLoop);
249 LOGGER.debug("control loop scan: transition from state {} to {} not completed", controlLoop.getState(),
250 controlLoop.getOrderedState());
252 var nextSpNotCompleted = ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())
253 || ControlLoopState.PASSIVE2RUNNING.equals(controlLoop.getState()) ? minSpNotCompleted
256 var firstStartPhase = ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())
257 || ControlLoopState.PASSIVE2RUNNING.equals(controlLoop.getState()) ? defaultMin
260 if (nextSpNotCompleted != phaseMap.getOrDefault(controlLoop.getKey().asIdentifier(), firstStartPhase)) {
261 phaseMap.put(controlLoop.getKey().asIdentifier(), nextSpNotCompleted);
262 sendControlLoopMsg(controlLoop, nextSpNotCompleted);
263 } else if (counterCheck) {
264 phaseMap.put(controlLoop.getKey().asIdentifier(), nextSpNotCompleted);
265 handleCounter(controlLoop, nextSpNotCompleted);
270 private void clearFaultAndCounter(ControlLoop controlLoop) {
271 controlLoopCounter.clear(controlLoop.getKey().asIdentifier());
275 private void handleCounter(ControlLoop controlLoop, int startPhase) {
276 ToscaConceptIdentifier id = controlLoop.getKey().asIdentifier();
277 if (controlLoopCounter.isFault(id)) {
278 LOGGER.debug("report ControlLoop fault");
282 if (controlLoopCounter.getDuration(id) > controlLoopCounter.getMaxWaitMs()) {
283 if (controlLoopCounter.count(id)) {
284 phaseMap.put(id, startPhase);
285 sendControlLoopMsg(controlLoop, startPhase);
287 LOGGER.debug("report ControlLoop fault");
288 controlLoopCounter.setFault(id);
293 private void sendControlLoopMsg(ControlLoop controlLoop, int startPhase) {
294 if (ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
295 LOGGER.debug("retry message ControlLoopUpdate");
296 controlLoopUpdatePublisher.send(controlLoop, startPhase);
298 LOGGER.debug("retry message ControlLoopStateChange");
299 controlLoopStateChangePublisher.send(controlLoop, startPhase);