a0533799116135a55d19119131b7f1cadb9856e3
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.controlloop.runtime.supervision;
22
23 import java.util.List;
24 import org.apache.commons.lang3.tuple.Pair;
25 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
26 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
27 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
28 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
29 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus;
30 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
31 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider;
32 import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
33 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopStateChangePublisher;
34 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopUpdatePublisher;
35 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusReqPublisher;
36 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantUpdatePublisher;
37 import org.onap.policy.models.base.PfModelException;
38 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.stereotype.Component;
42
43 /**
44  * This class is used to scan the control loops in the database and check if they are in the correct state.
45  */
46 @Component
47 public class SupervisionScanner {
48     private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class);
49
50     private HandleCounter<ToscaConceptIdentifier> controlLoopCounter = new HandleCounter<>();
51     private HandleCounter<ToscaConceptIdentifier> participantStatusCounter = new HandleCounter<>();
52     private HandleCounter<Pair<ToscaConceptIdentifier, ToscaConceptIdentifier>> participantUpdateCounter =
53             new HandleCounter<>();
54
55     private final ControlLoopProvider controlLoopProvider;
56     private final ControlLoopStateChangePublisher controlLoopStateChangePublisher;
57     private final ControlLoopUpdatePublisher controlLoopUpdatePublisher;
58     private final ParticipantProvider participantProvider;
59     private final ParticipantStatusReqPublisher participantStatusReqPublisher;
60     private final ParticipantUpdatePublisher participantUpdatePublisher;
61
62     private final long maxWaitMs;
63
64     /**
65      * Constructor for instantiating SupervisionScanner.
66      *
67      * @param controlLoopProvider the provider to use to read control loops from the database
68      * @param controlLoopStateChangePublisher the ControlLoop StateChange Publisher
69      * @param controlLoopUpdatePublisher the ControlLoopUpdate Publisher
70      * @param participantProvider the Participant Provider
71      * @param participantStatusReqPublisher the Participant StatusReq Publisher
72      * @param participantUpdatePublisher the Participant Update Publisher
73      * @param clRuntimeParameterGroup the parameters for the control loop runtime
74      */
75     public SupervisionScanner(final ControlLoopProvider controlLoopProvider,
76             final ControlLoopStateChangePublisher controlLoopStateChangePublisher,
77             ControlLoopUpdatePublisher controlLoopUpdatePublisher, ParticipantProvider participantProvider,
78             ParticipantStatusReqPublisher participantStatusReqPublisher,
79             ParticipantUpdatePublisher participantUpdatePublisher,
80             final ClRuntimeParameterGroup clRuntimeParameterGroup) {
81         this.controlLoopProvider = controlLoopProvider;
82         this.controlLoopStateChangePublisher = controlLoopStateChangePublisher;
83         this.controlLoopUpdatePublisher = controlLoopUpdatePublisher;
84         this.participantProvider = participantProvider;
85         this.participantStatusReqPublisher = participantStatusReqPublisher;
86         this.participantUpdatePublisher = participantUpdatePublisher;
87
88         controlLoopCounter.setMaxRetryCount(
89                 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
90         controlLoopCounter
91                 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
92
93         participantUpdateCounter.setMaxRetryCount(
94                 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
95         participantUpdateCounter
96                 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
97
98         participantStatusCounter.setMaxRetryCount(
99                 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
100         participantStatusCounter
101                 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
102
103         maxWaitMs = clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs();
104     }
105
106     /**
107      * Run Scanning.
108      *
109      * @param counterCheck if true activate counter and retry
110      */
111     public void run(boolean counterCheck) {
112         LOGGER.debug("Scanning control loops in the database . . .");
113
114         if (counterCheck) {
115             try {
116                 for (Participant participant : participantProvider.getParticipants(null, null)) {
117                     scanParticipantStatus(participant);
118                 }
119             } catch (PfModelException pfme) {
120                 LOGGER.warn("error reading participant from database", pfme);
121                 return;
122             }
123         }
124
125         try {
126             for (ControlLoop controlLoop : controlLoopProvider.getControlLoops(null, null)) {
127                 scanControlLoop(controlLoop, counterCheck);
128             }
129         } catch (PfModelException pfme) {
130             LOGGER.warn("error reading control loops from database", pfme);
131         }
132         if (counterCheck) {
133             scanParticipantUpdate();
134         }
135
136         LOGGER.debug("Control loop scan complete . . .");
137     }
138
139     private void scanParticipantUpdate() {
140         LOGGER.debug("Scanning participants to update . . .");
141
142         for (var id : participantUpdateCounter.keySet()) {
143             if (participantUpdateCounter.isFault(id)) {
144                 LOGGER.debug("report Participant Update fault");
145
146             } else if (participantUpdateCounter.getDuration(id) > maxWaitMs) {
147
148                 if (participantUpdateCounter.count(id)) {
149                     LOGGER.debug("retry message ParticipantUpdate");
150                     participantUpdatePublisher.send(id.getLeft(), id.getRight(), true);
151                 } else {
152                     LOGGER.debug("report Participant Update fault");
153                     participantUpdateCounter.setFault(id);
154                 }
155             }
156         }
157
158         LOGGER.debug("Participants to update scan complete . . .");
159     }
160
161     private void scanParticipantStatus(Participant participant) throws PfModelException {
162         ToscaConceptIdentifier id = participant.getKey().asIdentifier();
163         if (participantStatusCounter.isFault(id)) {
164             LOGGER.debug("report Participant fault");
165             return;
166         }
167         if (participantStatusCounter.getDuration(id) > maxWaitMs) {
168             if (participantStatusCounter.count(id)) {
169                 LOGGER.debug("retry message ParticipantStatusReq");
170                 participantStatusReqPublisher.send(id);
171                 participant.setHealthStatus(ParticipantHealthStatus.NOT_HEALTHY);
172             } else {
173                 LOGGER.debug("report Participant fault");
174                 participantStatusCounter.setFault(id);
175                 participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
176             }
177             participantProvider.updateParticipants(List.of(participant));
178         }
179     }
180
181     /**
182      * handle participant Status message.
183      */
184     public void handleParticipantStatus(ToscaConceptIdentifier id) {
185         participantStatusCounter.clear(id);
186     }
187
188     public void handleParticipantRegister(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
189         participantUpdateCounter.clear(id);
190     }
191
192     public void handleParticipantUpdateAck(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
193         participantUpdateCounter.remove(id);
194     }
195
196     private void scanControlLoop(final ControlLoop controlLoop, boolean counterCheck) throws PfModelException {
197         LOGGER.debug("scanning control loop {} . . .", controlLoop.getKey().asIdentifier());
198
199         if (controlLoop.getState().equals(controlLoop.getOrderedState().asState())) {
200             LOGGER.debug("control loop {} scanned, OK", controlLoop.getKey().asIdentifier());
201
202             // Clear missed report counter on Control Loop
203             clearFaultAndCounter(controlLoop);
204             return;
205         }
206
207         boolean completed = true;
208         for (ControlLoopElement element : controlLoop.getElements().values()) {
209             if (!element.getState().equals(element.getOrderedState().asState())) {
210                 completed = false;
211                 break;
212             }
213         }
214
215         if (completed) {
216             LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
217                     controlLoop.getOrderedState());
218
219             controlLoop.setState(controlLoop.getOrderedState().asState());
220             controlLoopProvider.updateControlLoop(controlLoop);
221
222             // Clear missed report counter on Control Loop
223             clearFaultAndCounter(controlLoop);
224         } else {
225             LOGGER.debug("control loop scan: transition from state {} to {} not completed", controlLoop.getState(),
226                     controlLoop.getOrderedState());
227             if (counterCheck) {
228                 handleCounter(controlLoop);
229             }
230         }
231     }
232
233     private void clearFaultAndCounter(ControlLoop controlLoop) {
234         controlLoopCounter.clear(controlLoop.getKey().asIdentifier());
235     }
236
237     private void handleCounter(ControlLoop controlLoop) {
238         ToscaConceptIdentifier id = controlLoop.getKey().asIdentifier();
239         if (controlLoopCounter.isFault(id)) {
240             LOGGER.debug("report ControlLoop fault");
241             return;
242         }
243
244         if (controlLoopCounter.count(id)) {
245             if (ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
246                 LOGGER.debug("retry message ControlLoopUpdate");
247                 controlLoopUpdatePublisher.send(controlLoop);
248             } else {
249                 LOGGER.debug("retry message ControlLoopStateChange");
250                 controlLoopStateChangePublisher.send(controlLoop);
251             }
252         } else {
253             LOGGER.debug("report ControlLoop fault");
254             controlLoopCounter.setFault(id);
255         }
256     }
257 }