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