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.List;
26 import org.apache.commons.lang3.tuple.Pair;
27 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
28 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
29 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
30 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
31 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus;
32 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantUtils;
33 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
34 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider;
35 import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
36 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopStateChangePublisher;
37 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopUpdatePublisher;
38 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusReqPublisher;
39 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantUpdatePublisher;
40 import org.onap.policy.models.base.PfModelException;
41 import org.onap.policy.models.provider.PolicyModelsProvider;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
44 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.stereotype.Component;
50 * This class is used to scan the control loops in the database and check if they are in the correct state.
53 public class SupervisionScanner {
54 private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class);
56 private HandleCounter<ToscaConceptIdentifier> controlLoopCounter = new HandleCounter<>();
57 private HandleCounter<ToscaConceptIdentifier> participantStatusCounter = new HandleCounter<>();
58 private HandleCounter<Pair<ToscaConceptIdentifier, ToscaConceptIdentifier>> participantUpdateCounter =
59 new HandleCounter<>();
61 private final ControlLoopProvider controlLoopProvider;
62 private final PolicyModelsProvider modelsProvider;
63 private final ControlLoopStateChangePublisher controlLoopStateChangePublisher;
64 private final ControlLoopUpdatePublisher controlLoopUpdatePublisher;
65 private final ParticipantProvider participantProvider;
66 private final ParticipantStatusReqPublisher participantStatusReqPublisher;
67 private final ParticipantUpdatePublisher participantUpdatePublisher;
70 * Constructor for instantiating SupervisionScanner.
72 * @param controlLoopProvider the provider to use to read control loops from the database
73 * @param modelsProvider the Policy Models Provider
74 * @param controlLoopStateChangePublisher the ControlLoop StateChange Publisher
75 * @param controlLoopUpdatePublisher the ControlLoopUpdate Publisher
76 * @param participantProvider the Participant Provider
77 * @param participantStatusReqPublisher the Participant StatusReq Publisher
78 * @param participantUpdatePublisher the Participant Update Publisher
79 * @param clRuntimeParameterGroup the parameters for the control loop runtime
81 public SupervisionScanner(final ControlLoopProvider controlLoopProvider, PolicyModelsProvider modelsProvider,
82 final ControlLoopStateChangePublisher controlLoopStateChangePublisher,
83 ControlLoopUpdatePublisher controlLoopUpdatePublisher, ParticipantProvider participantProvider,
84 ParticipantStatusReqPublisher participantStatusReqPublisher,
85 ParticipantUpdatePublisher participantUpdatePublisher,
86 final ClRuntimeParameterGroup clRuntimeParameterGroup) {
87 this.controlLoopProvider = controlLoopProvider;
88 this.modelsProvider = modelsProvider;
89 this.controlLoopStateChangePublisher = controlLoopStateChangePublisher;
90 this.controlLoopUpdatePublisher = controlLoopUpdatePublisher;
91 this.participantProvider = participantProvider;
92 this.participantStatusReqPublisher = participantStatusReqPublisher;
93 this.participantUpdatePublisher = participantUpdatePublisher;
95 controlLoopCounter.setMaxRetryCount(
96 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
97 controlLoopCounter.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
99 participantUpdateCounter.setMaxRetryCount(
100 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
101 participantUpdateCounter
102 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
104 participantStatusCounter.setMaxRetryCount(
105 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
106 participantStatusCounter.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
112 * @param counterCheck if true activate counter and retry
114 public void run(boolean counterCheck) {
115 LOGGER.debug("Scanning control loops in the database . . .");
119 for (Participant participant : participantProvider.getParticipants(null, null)) {
120 scanParticipantStatus(participant);
122 } catch (PfModelException pfme) {
123 LOGGER.warn("error reading participant from database", pfme);
129 var list = modelsProvider.getServiceTemplateList(null, null);
130 if (list != null && !list.isEmpty()) {
131 ToscaServiceTemplate toscaServiceTemplate = list.get(0);
133 for (ControlLoop controlLoop : controlLoopProvider.getControlLoops(null, null)) {
134 scanControlLoop(controlLoop, toscaServiceTemplate, counterCheck);
137 } catch (PfModelException pfme) {
138 LOGGER.warn("error reading control loops from database", pfme);
142 scanParticipantUpdate();
145 LOGGER.debug("Control loop scan complete . . .");
148 private void scanParticipantUpdate() {
149 LOGGER.debug("Scanning participants to update . . .");
151 for (var id : participantUpdateCounter.keySet()) {
152 if (participantUpdateCounter.isFault(id)) {
153 LOGGER.debug("report Participant Update fault");
155 } else if (participantUpdateCounter.getDuration(id) > participantUpdateCounter.getMaxWaitMs()) {
157 if (participantUpdateCounter.count(id)) {
158 LOGGER.debug("retry message ParticipantUpdate");
159 participantUpdatePublisher.send(null, true);
161 LOGGER.debug("report Participant Update fault");
162 participantUpdateCounter.setFault(id);
167 LOGGER.debug("Participants to update scan complete . . .");
170 private void scanParticipantStatus(Participant participant) throws PfModelException {
171 ToscaConceptIdentifier id = participant.getKey().asIdentifier();
172 if (participantStatusCounter.isFault(id)) {
173 LOGGER.debug("report Participant fault");
176 if (participantStatusCounter.getDuration(id) > participantStatusCounter.getMaxWaitMs()) {
177 if (participantStatusCounter.count(id)) {
178 LOGGER.debug("retry message ParticipantStatusReq");
179 participantStatusReqPublisher.send(id);
180 participant.setHealthStatus(ParticipantHealthStatus.NOT_HEALTHY);
182 LOGGER.debug("report Participant fault");
183 participantStatusCounter.setFault(id);
184 participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
186 participantProvider.updateParticipants(List.of(participant));
191 * handle participant Status message.
193 public void handleParticipantStatus(ToscaConceptIdentifier id) {
194 participantStatusCounter.clear(id);
197 public void handleParticipantRegister(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
198 participantUpdateCounter.clear(id);
201 public void handleParticipantUpdateAck(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
202 participantUpdateCounter.remove(id);
205 private void scanControlLoop(final ControlLoop controlLoop, ToscaServiceTemplate toscaServiceTemplate,
206 boolean counterCheck) throws PfModelException {
207 LOGGER.debug("scanning control loop {} . . .", controlLoop.getKey().asIdentifier());
209 if (controlLoop.getState().equals(controlLoop.getOrderedState().asState())) {
210 LOGGER.debug("control loop {} scanned, OK", controlLoop.getKey().asIdentifier());
212 // Clear missed report counter on Control Loop
213 clearFaultAndCounter(controlLoop);
217 var completed = true;
218 var minSpNotCompleted = 1000; // min startPhase not completed
219 for (ControlLoopElement element : controlLoop.getElements().values()) {
220 if (!element.getState().equals(element.getOrderedState().asState())) {
222 ToscaNodeTemplate toscaNodeTemplate = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates()
223 .get(element.getDefinition().getName());
224 int startPhase = ParticipantUtils.findStartPhase(toscaNodeTemplate.getProperties());
225 minSpNotCompleted = Math.min(minSpNotCompleted, startPhase);
231 LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
232 controlLoop.getOrderedState());
234 controlLoop.setState(controlLoop.getOrderedState().asState());
235 controlLoopProvider.updateControlLoop(controlLoop);
237 // Clear missed report counter on Control Loop
238 clearFaultAndCounter(controlLoop);
240 LOGGER.debug("control loop scan: transition from state {} to {} not completed", controlLoop.getState(),
241 controlLoop.getOrderedState());
243 handleCounter(controlLoop, minSpNotCompleted);
248 private void clearFaultAndCounter(ControlLoop controlLoop) {
249 controlLoopCounter.clear(controlLoop.getKey().asIdentifier());
252 private void handleCounter(ControlLoop controlLoop, int startPhase) {
253 ToscaConceptIdentifier id = controlLoop.getKey().asIdentifier();
254 if (controlLoopCounter.isFault(id)) {
255 LOGGER.debug("report ControlLoop fault");
259 if (controlLoopCounter.getDuration(id) > controlLoopCounter.getMaxWaitMs()) {
260 if (controlLoopCounter.count(id)) {
261 if (ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
262 LOGGER.debug("retry message ControlLoopUpdate");
263 controlLoopUpdatePublisher.send(controlLoop, startPhase);
265 LOGGER.debug("retry message ControlLoopStateChange");
266 controlLoopStateChangePublisher.send(controlLoop);
269 LOGGER.debug("report ControlLoop fault");
270 controlLoopCounter.setFault(id);