7be407c3fee2c274e5740f8fc10edcaa01a12f14
[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.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
25 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
26 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
27 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
28 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus;
29 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
30 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider;
31 import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
32 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopStateChangePublisher;
33 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ControlLoopUpdatePublisher;
34 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantStatusReqPublisher;
35 import org.onap.policy.models.base.PfModelException;
36 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.springframework.stereotype.Component;
40
41 /**
42  * This class is used to scan the control loops in the database and check if they are in the correct state.
43  */
44 @Component
45 public class SupervisionScanner {
46     private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionScanner.class);
47
48     private HandleCounter<ToscaConceptIdentifier> controlLoopCounter = new HandleCounter<>();
49     private HandleCounter<ToscaConceptIdentifier> participantCounter = new HandleCounter<>();
50
51     private final ControlLoopProvider controlLoopProvider;
52     private final ControlLoopStateChangePublisher controlLoopStateChangePublisher;
53     private final ControlLoopUpdatePublisher controlLoopUpdatePublisher;
54     private final ParticipantProvider participantProvider;
55     private final ParticipantStatusReqPublisher participantStatusReqPublisher;
56
57     private final long maxMessageAgeMs;
58
59     /**
60      * Constructor for instantiating SupervisionScanner.
61      *
62      * @param controlLoopProvider the provider to use to read control loops from the database
63      * @param controlLoopStateChangePublisher the ControlLoop StateChange Publisher
64      * @param controlLoopUpdatePublisher the ControlLoopUpdate Publisher
65      * @param participantProvider the Participant Provider
66      * @param participantStatusReqPublisher the Participant StatusReq Publisher
67      * @param clRuntimeParameterGroup the parameters for the control loop runtime
68      */
69     public SupervisionScanner(final ControlLoopProvider controlLoopProvider,
70             final ControlLoopStateChangePublisher controlLoopStateChangePublisher,
71             ControlLoopUpdatePublisher controlLoopUpdatePublisher, ParticipantProvider participantProvider,
72             ParticipantStatusReqPublisher participantStatusReqPublisher,
73             final ClRuntimeParameterGroup clRuntimeParameterGroup) {
74         this.controlLoopProvider = controlLoopProvider;
75         this.controlLoopStateChangePublisher = controlLoopStateChangePublisher;
76         this.controlLoopUpdatePublisher = controlLoopUpdatePublisher;
77         this.participantProvider = participantProvider;
78         this.participantStatusReqPublisher = participantStatusReqPublisher;
79
80         controlLoopCounter.setMaxRetryCount(
81                 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
82         controlLoopCounter
83                 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
84
85         participantCounter.setMaxRetryCount(
86                 clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxRetryCount());
87         participantCounter
88                 .setMaxWaitMs(clRuntimeParameterGroup.getParticipantParameters().getUpdateParameters().getMaxWaitMs());
89
90         maxMessageAgeMs = clRuntimeParameterGroup.getParticipantParameters().getMaxMessageAgeMs();
91     }
92
93     /**
94      * Run Scanning.
95      *
96      * @param counterCheck if true activate counter and retry
97      */
98     public void run(boolean counterCheck) {
99         LOGGER.debug("Scanning control loops in the database . . .");
100
101         if (counterCheck) {
102             try {
103                 for (Participant participant : participantProvider.getParticipants(null, null)) {
104                     scanParticipant(participant);
105                 }
106             } catch (PfModelException pfme) {
107                 LOGGER.warn("error reading participant from database", pfme);
108                 return;
109             }
110         }
111
112         try {
113             for (ControlLoop controlLoop : controlLoopProvider.getControlLoops(null, null)) {
114                 scanControlLoop(controlLoop, counterCheck);
115             }
116         } catch (PfModelException pfme) {
117             LOGGER.warn("error reading control loops from database", pfme);
118         }
119
120         LOGGER.debug("Control loop scan complete . . .");
121     }
122
123     private void scanParticipant(Participant participant) throws PfModelException {
124         ToscaConceptIdentifier id = participant.getKey().asIdentifier();
125         if (participantCounter.isFault(id)) {
126             LOGGER.debug("report Participant fault");
127             return;
128         }
129         if (participantCounter.getDuration(id) > maxMessageAgeMs) {
130             if (participantCounter.count(id)) {
131                 LOGGER.debug("retry message ParticipantStatusReq");
132                 participantStatusReqPublisher.send(id);
133                 participant.setHealthStatus(ParticipantHealthStatus.NOT_HEALTHY);
134             } else {
135                 LOGGER.debug("report Participant fault");
136                 participantCounter.setFault(id);
137                 participant.setHealthStatus(ParticipantHealthStatus.OFF_LINE);
138             }
139             participantProvider.updateParticipants(List.of(participant));
140         }
141     }
142
143     /**
144      * handle participant Status message.
145      */
146     public void handleParticipantStatus(ToscaConceptIdentifier id) {
147         participantCounter.clear(id);
148     }
149
150     private void scanControlLoop(final ControlLoop controlLoop, boolean counterCheck) throws PfModelException {
151         LOGGER.debug("scanning control loop {} . . .", controlLoop.getKey().asIdentifier());
152
153         if (controlLoop.getState().equals(controlLoop.getOrderedState().asState())) {
154             LOGGER.debug("control loop {} scanned, OK", controlLoop.getKey().asIdentifier());
155
156             // Clear missed report counter on Control Loop
157             clearFaultAndCounter(controlLoop);
158             return;
159         }
160
161         boolean completed = true;
162         for (ControlLoopElement element : controlLoop.getElements().values()) {
163             if (!element.getState().equals(element.getOrderedState().asState())) {
164                 completed = false;
165                 break;
166             }
167         }
168
169         if (completed) {
170             LOGGER.debug("control loop scan: transition from state {} to {} completed", controlLoop.getState(),
171                     controlLoop.getOrderedState());
172
173             controlLoop.setState(controlLoop.getOrderedState().asState());
174             controlLoopProvider.updateControlLoop(controlLoop);
175
176             // Clear missed report counter on Control Loop
177             clearFaultAndCounter(controlLoop);
178         } else {
179             LOGGER.debug("control loop scan: transition from state {} to {} not completed", controlLoop.getState(),
180                     controlLoop.getOrderedState());
181             if (counterCheck) {
182                 handleCounter(controlLoop);
183             }
184         }
185     }
186
187     private void clearFaultAndCounter(ControlLoop controlLoop) {
188         controlLoopCounter.clear(controlLoop.getKey().asIdentifier());
189     }
190
191     private void handleCounter(ControlLoop controlLoop) {
192         ToscaConceptIdentifier id = controlLoop.getKey().asIdentifier();
193         if (controlLoopCounter.isFault(id)) {
194             LOGGER.debug("report ControlLoop fault");
195             return;
196         }
197
198         if (controlLoopCounter.count(id)) {
199             if (ControlLoopState.UNINITIALISED2PASSIVE.equals(controlLoop.getState())) {
200                 LOGGER.debug("retry message ControlLoopUpdate");
201                 controlLoopUpdatePublisher.send(controlLoop);
202             } else {
203                 LOGGER.debug("retry message ControlLoopStateChange");
204                 controlLoopStateChangePublisher.send(controlLoop);
205             }
206         } else {
207             LOGGER.debug("report ControlLoop fault");
208             controlLoopCounter.setFault(id);
209         }
210     }
211 }