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.models.controlloop.persistence.provider.ServiceTemplateProvider;
38 import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
39 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopStateChangePublisher;
40 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopUpdatePublisher;
41 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusReqPublisher;
42 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantUpdatePublisher;
43 import org.onap.policy.models.base.PfModelException;
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 ServiceTemplateProvider serviceTemplateProvider;
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 serviceTemplateProvider 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,
86 ServiceTemplateProvider serviceTemplateProvider,
87 final ControlLoopStateChangePublisher controlLoopStateChangePublisher,
88 ControlLoopUpdatePublisher controlLoopUpdatePublisher, ParticipantProvider participantProvider,
89 ParticipantStatusReqPublisher participantStatusReqPublisher,
90 ParticipantUpdatePublisher participantUpdatePublisher,
91 final ClRuntimeParameterGroup clRuntimeParameterGroup) {
92 this.controlLoopProvider = controlLoopProvider;
93 this.serviceTemplateProvider = serviceTemplateProvider;
94 this.controlLoopStateChangePublisher = controlLoopStateChangePublisher;
95 this.controlLoopUpdatePublisher = controlLoopUpdatePublisher;
96 this.participantProvider = participantProvider;
97 this.participantStatusReqPublisher = participantStatusReqPublisher;
98 this.participantUpdatePublisher = participantUpdatePublisher;
100 controlLoopCounter.setMaxRetryCount(
101 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
102 controlLoopCounter.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
104 participantUpdateCounter.setMaxRetryCount(
105 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
106 participantUpdateCounter
107 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
109 participantStatusCounter.setMaxRetryCount(
110 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
111 participantStatusCounter.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
117 * @param counterCheck if true activate counter and retry
119 public void run(boolean counterCheck) {
120 LOGGER.debug("Scanning control loops in the database . . .");
124 for (Participant participant : participantProvider.getParticipants(null, null)) {
125 scanParticipantStatus(participant);
127 } catch (PfModelException pfme) {
128 LOGGER.warn("error reading participant from database", pfme);
134 var list = serviceTemplateProvider.getServiceTemplateList(null, null);
135 if (list != null && !list.isEmpty()) {
136 ToscaServiceTemplate toscaServiceTemplate = list.get(0);
138 for (ControlLoop controlLoop : controlLoopProvider.getControlLoops(null, null)) {
139 scanControlLoop(controlLoop, toscaServiceTemplate, counterCheck);
142 } catch (PfModelException pfme) {
143 LOGGER.warn("error reading control loops from database", pfme);
147 scanParticipantUpdate();
150 LOGGER.debug("Control loop scan complete . . .");
153 private void scanParticipantUpdate() {
154 LOGGER.debug("Scanning participants to update . . .");
156 for (var id : participantUpdateCounter.keySet()) {
157 if (participantUpdateCounter.isFault(id)) {
158 LOGGER.debug("report Participant Update fault");
160 } else if (participantUpdateCounter.getDuration(id) > participantUpdateCounter.getMaxWaitMs()) {
162 if (participantUpdateCounter.count(id)) {
163 LOGGER.debug("retry message ParticipantUpdate");
164 participantUpdatePublisher.sendCommissioning(null, null, id.getLeft(), id.getRight());
166 LOGGER.debug("report Participant Update fault");
167 participantUpdateCounter.setFault(id);
172 LOGGER.debug("Participants to update scan complete . . .");
175 private void scanParticipantStatus(Participant participant) throws PfModelException {
176 ToscaConceptIdentifier id = participant.getKey().asIdentifier();
177 if (participantStatusCounter.isFault(id)) {
178 LOGGER.debug("report Participant fault");
181 if (participantStatusCounter.getDuration(id) > participantStatusCounter.getMaxWaitMs()) {
182 if (participantStatusCounter.count(id)) {
183 LOGGER.debug("retry message ParticipantStatusReq");
184 participantStatusReqPublisher.send(id);
185 participant.setHealthStatus(ParticipantHealthStatus.NOT_HEALTHY);
187 LOGGER.debug("report Participant fault");
188 participantStatusCounter.setFault(id);
189 participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
191 participantProvider.updateParticipants(List.of(participant));
196 * handle participant Status message.
198 public void handleParticipantStatus(ToscaConceptIdentifier id) {
199 participantStatusCounter.clear(id);
202 public void handleParticipantRegister(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
203 participantUpdateCounter.clear(id);
206 public void handleParticipantUpdateAck(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
207 participantUpdateCounter.remove(id);
210 private void scanControlLoop(final ControlLoop controlLoop, ToscaServiceTemplate toscaServiceTemplate,
211 boolean counterCheck) throws PfModelException {
212 LOGGER.debug("scanning control loop {} . . .", controlLoop.getKey().asIdentifier());
214 if (controlLoop.getState().equals(controlLoop.getOrderedState().asState())) {
215 LOGGER.debug("control loop {} scanned, OK", controlLoop.getKey().asIdentifier());
217 // Clear missed report counter on Control Loop
218 clearFaultAndCounter(controlLoop);
222 var completed = true;
223 var minSpNotCompleted = 1000; // min startPhase not completed
224 var maxSpNotCompleted = 0; // max startPhase not completed
225 var defaultMin = 1000; // min startPhase
226 var defaultMax = 0; // max startPhase
227 for (ControlLoopElement element : controlLoop.getElements().values()) {
228 ToscaNodeTemplate toscaNodeTemplate = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates()
229 .get(element.getDefinition().getName());
230 int startPhase = ParticipantUtils.findStartPhase(toscaNodeTemplate.getProperties());
231 defaultMin = Math.min(defaultMin, startPhase);
232 defaultMax = Math.max(defaultMax, startPhase);
233 if (!element.getState().equals(element.getOrderedState().asState())) {
235 minSpNotCompleted = Math.min(minSpNotCompleted, startPhase);
236 maxSpNotCompleted = Math.max(maxSpNotCompleted, startPhase);
241 LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
242 controlLoop.getOrderedState());
244 controlLoop.setState(controlLoop.getOrderedState().asState());
245 controlLoopProvider.updateControlLoop(controlLoop);
247 // Clear missed report counter on Control Loop
248 clearFaultAndCounter(controlLoop);
250 LOGGER.debug("control loop scan: transition from state {} to {} not completed", controlLoop.getState(),
251 controlLoop.getOrderedState());
253 var nextSpNotCompleted = ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())
254 || ControlLoopState.PASSIVE2RUNNING.equals(controlLoop.getState()) ? minSpNotCompleted
257 var firstStartPhase = ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())
258 || ControlLoopState.PASSIVE2RUNNING.equals(controlLoop.getState()) ? defaultMin
261 if (nextSpNotCompleted != phaseMap.getOrDefault(controlLoop.getKey().asIdentifier(), firstStartPhase)) {
262 phaseMap.put(controlLoop.getKey().asIdentifier(), nextSpNotCompleted);
263 sendControlLoopMsg(controlLoop, nextSpNotCompleted);
264 } else if (counterCheck) {
265 phaseMap.put(controlLoop.getKey().asIdentifier(), nextSpNotCompleted);
266 handleCounter(controlLoop, nextSpNotCompleted);
271 private void clearFaultAndCounter(ControlLoop controlLoop) {
272 controlLoopCounter.clear(controlLoop.getKey().asIdentifier());
276 private void handleCounter(ControlLoop controlLoop, int startPhase) {
277 ToscaConceptIdentifier id = controlLoop.getKey().asIdentifier();
278 if (controlLoopCounter.isFault(id)) {
279 LOGGER.debug("report ControlLoop fault");
283 if (controlLoopCounter.getDuration(id) > controlLoopCounter.getMaxWaitMs()) {
284 if (controlLoopCounter.count(id)) {
285 phaseMap.put(id, startPhase);
286 sendControlLoopMsg(controlLoop, startPhase);
288 LOGGER.debug("report ControlLoop fault");
289 controlLoopCounter.setFault(id);
294 private void sendControlLoopMsg(ControlLoop controlLoop, int startPhase) {
295 if (ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
296 LOGGER.debug("retry message ControlLoopUpdate");
297 controlLoopUpdatePublisher.send(controlLoop, startPhase);
299 LOGGER.debug("retry message ControlLoopStateChange");
300 controlLoopStateChangePublisher.send(controlLoop, startPhase);