d13d66c5d47a89a05289b3af562f599b13205f87
[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     /**
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.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
91
92         participantUpdateCounter.setMaxRetryCount(
93                 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
94         participantUpdateCounter
95                 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
96
97         participantStatusCounter.setMaxRetryCount(
98                 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
99         participantStatusCounter.setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs());
100     }
101
102     /**
103      * Run Scanning.
104      *
105      * @param counterCheck if true activate counter and retry
106      */
107     public void run(boolean counterCheck) {
108         LOGGER.debug("Scanning control loops in the database . . .");
109
110         if (counterCheck) {
111             try {
112                 for (Participant participant : participantProvider.getParticipants(null, null)) {
113                     scanParticipantStatus(participant);
114                 }
115             } catch (PfModelException pfme) {
116                 LOGGER.warn("error reading participant from database", pfme);
117                 return;
118             }
119         }
120
121         try {
122             for (ControlLoop controlLoop : controlLoopProvider.getControlLoops(null, null)) {
123                 scanControlLoop(controlLoop, counterCheck);
124             }
125         } catch (PfModelException pfme) {
126             LOGGER.warn("error reading control loops from database", pfme);
127         }
128
129         if (counterCheck) {
130             scanParticipantUpdate();
131         }
132
133         LOGGER.debug("Control loop scan complete . . .");
134     }
135
136     private void scanParticipantUpdate() {
137         LOGGER.debug("Scanning participants to update . . .");
138
139         for (var id : participantUpdateCounter.keySet()) {
140             if (participantUpdateCounter.isFault(id)) {
141                 LOGGER.debug("report Participant Update fault");
142
143             } else if (participantUpdateCounter.getDuration(id) > participantUpdateCounter.getMaxWaitMs()) {
144
145                 if (participantUpdateCounter.count(id)) {
146                     LOGGER.debug("retry message ParticipantUpdate");
147                     participantUpdatePublisher.send(id.getLeft(), id.getRight(), true);
148                 } else {
149                     LOGGER.debug("report Participant Update fault");
150                     participantUpdateCounter.setFault(id);
151                 }
152             }
153         }
154
155         LOGGER.debug("Participants to update scan complete . . .");
156     }
157
158     private void scanParticipantStatus(Participant participant) throws PfModelException {
159         ToscaConceptIdentifier id = participant.getKey().asIdentifier();
160         if (participantStatusCounter.isFault(id)) {
161             LOGGER.debug("report Participant fault");
162             return;
163         }
164         if (participantStatusCounter.getDuration(id) > participantStatusCounter.getMaxWaitMs()) {
165             if (participantStatusCounter.count(id)) {
166                 LOGGER.debug("retry message ParticipantStatusReq");
167                 participantStatusReqPublisher.send(id);
168                 participant.setHealthStatus(ParticipantHealthStatus.NOT_HEALTHY);
169             } else {
170                 LOGGER.debug("report Participant fault");
171                 participantStatusCounter.setFault(id);
172                 participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
173             }
174             participantProvider.updateParticipants(List.of(participant));
175         }
176     }
177
178     /**
179      * handle participant Status message.
180      */
181     public void handleParticipantStatus(ToscaConceptIdentifier id) {
182         participantStatusCounter.clear(id);
183     }
184
185     public void handleParticipantRegister(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
186         participantUpdateCounter.clear(id);
187     }
188
189     public void handleParticipantUpdateAck(Pair<ToscaConceptIdentifier, ToscaConceptIdentifier> id) {
190         participantUpdateCounter.remove(id);
191     }
192
193     private void scanControlLoop(final ControlLoop controlLoop, boolean counterCheck) throws PfModelException {
194         LOGGER.debug("scanning control loop {} . . .", controlLoop.getKey().asIdentifier());
195
196         if (controlLoop.getState().equals(controlLoop.getOrderedState().asState())) {
197             LOGGER.debug("control loop {} scanned, OK", controlLoop.getKey().asIdentifier());
198
199             // Clear missed report counter on Control Loop
200             clearFaultAndCounter(controlLoop);
201             return;
202         }
203
204         var completed = true;
205         for (ControlLoopElement element : controlLoop.getElements().values()) {
206             if (!element.getState().equals(element.getOrderedState().asState())) {
207                 completed = false;
208                 break;
209             }
210         }
211
212         if (completed) {
213             LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
214                     controlLoop.getOrderedState());
215
216             controlLoop.setState(controlLoop.getOrderedState().asState());
217             controlLoopProvider.updateControlLoop(controlLoop);
218
219             // Clear missed report counter on Control Loop
220             clearFaultAndCounter(controlLoop);
221         } else {
222             LOGGER.debug("control loop scan: transition from state {} to {} not completed", controlLoop.getState(),
223                     controlLoop.getOrderedState());
224             if (counterCheck) {
225                 handleCounter(controlLoop);
226             }
227         }
228     }
229
230     private void clearFaultAndCounter(ControlLoop controlLoop) {
231         controlLoopCounter.clear(controlLoop.getKey().asIdentifier());
232     }
233
234     private void handleCounter(ControlLoop controlLoop) {
235         ToscaConceptIdentifier id = controlLoop.getKey().asIdentifier();
236         if (controlLoopCounter.isFault(id)) {
237             LOGGER.debug("report ControlLoop fault");
238             return;
239         }
240
241         if (controlLoopCounter.getDuration(id) > controlLoopCounter.getMaxWaitMs()) {
242             if (controlLoopCounter.count(id)) {
243                 if (ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
244                     LOGGER.debug("retry message ControlLoopUpdate");
245                     controlLoopUpdatePublisher.send(controlLoop);
246                 } else {
247                     LOGGER.debug("retry message ControlLoopStateChange");
248                     controlLoopStateChangePublisher.send(controlLoop);
249                 }
250             } else {
251                 LOGGER.debug("report ControlLoop fault");
252                 controlLoopCounter.setFault(id);
253             }
254         }
255     }
256 }