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