1 /*******************************************************************************
2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2022 Huawei Canada Limited.
6 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
7 * ==============================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 *******************************************************************************/
22 package org.onap.slice.analysis.ms.service.ccvpn;
24 import com.google.gson.JsonObject;
25 import org.onap.slice.analysis.ms.models.Configuration;
26 import org.onap.slice.analysis.ms.service.PolicyService;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.springframework.beans.factory.annotation.Autowired;
30 import org.springframework.stereotype.Component;
32 import javax.annotation.PostConstruct;
33 import java.util.Arrays;
35 import java.util.TreeMap;
36 import java.util.stream.Collectors;
39 * Threshold strategy can be configured via configuration
40 * If "sliceanalysisms.ccvpnEvalStrategy" is set to "FlexibleThresholdStrategy", then this class is triggered.
43 public class FlexibleThresholdStrategy implements EvaluationStrategy{
44 private static Logger log = LoggerFactory.getLogger(FixedUpperBoundStrategy.class);
45 private Configuration configuration;
46 private static final String TYPE_NAME = "FlexibleThresholdStrategy";
47 private static final String SERVICE_INSTANCE_LOCATION_ID = "service-instance-location-id";
48 private static final String BANDWIDTH_TOTAL = "bandwidth-total";
51 * Percentage threshold of bandwidth increase adjustment.
53 private static double upperThreshold;
56 * Percentage threshold of bandwidth decrease adjustment.
58 private static double lowerThreshold;
61 * Precision of bandwidth evaluation and adjustment.
63 private static double precision; // in Mbps;
66 BandwidthEvaluator bandwidthEvaluator;
69 CCVPNPmDatastore ccvpnPmDatastore;
72 PolicyService policyService;
80 * Periodically ensure endpoint bw adjustment is under assurance.
81 * This method will be invoked when FlexibleThresholdStrategy is set.
85 public void execute(Event event){
86 if (event.type() == SimpleEvent.Type.PERIODIC_CHECK && isPeriodicCheckOn()){
87 log.info("=== Processing new periodic check request: {} ===", event.time());
88 Map<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> usedBwMap = ccvpnPmDatastore.getUsedBwMap();
89 Map<String, Integer> candidate = new TreeMap<>();
90 for(Map.Entry<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> entry: usedBwMap.entrySet()) {
91 String serviceId = entry.getKey().getCllId();
92 Object[] usedBws = entry.getValue().tryReadToArray();
93 // Judge whether this cll is under closed loop assurance
94 if (!ccvpnPmDatastore.getClosedloopStatus(serviceId)) {
95 log.info("CCVPN Evaluator Output: service {}, closed loop bw modification is off.", serviceId);
98 if (usedBws == null) {
99 // Not enough data for evaluating
100 log.info("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId);
103 if (ccvpnPmDatastore.getProvBwOfSvc(serviceId) == 0) {
104 // Max bandwidth not cached yet
105 log.info("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId);
106 post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, serviceId));
109 double avg = Arrays.stream(usedBws)
110 .mapToInt(o -> (int) o)
113 int provBw = ccvpnPmDatastore.getProvBwOfSvc(serviceId);
114 int originalBw = ccvpnPmDatastore.getOriginalBw(serviceId);
116 if(needIncrease(serviceId, avg, provBw)){
117 int newBw = (int) (Math.ceil((avg / upperThreshold) * 1.2 / precision) * precision);
118 log.info("For cll {}, going to increase bw to {}", serviceId, newBw);
119 candidate.put(serviceId, Math.max(candidate.getOrDefault(serviceId, 0), newBw));
121 if(needDecrease(serviceId, avg, provBw, originalBw)) {
122 int newBw = Math.max((int) (Math.ceil(provBw * 0.5)), originalBw);
123 log.info("For cll {}, going to decrease bw to {}", serviceId, newBw);
124 candidate.put(serviceId, Math.max(candidate.getOrDefault(serviceId, 0), newBw));
128 // check svc under maintenance
129 Map<String , ServiceState> svcUnderMaintenance = getServicesUnderMaintenance();
130 for (Map.Entry<String, ServiceState> entry: svcUnderMaintenance.entrySet()){
131 candidate.putIfAbsent(entry.getKey(), 0);
133 // fetch the provisioned bandwidth info if underMaintenance; otherwise send modification request
134 for(Map.Entry<String, Integer> entry: candidate.entrySet()) {
135 //still doing adjustment
136 String cllId = entry.getKey();
137 Integer newBw = entry.getValue();
138 if(!ccvpnPmDatastore.getClosedloopStatus(cllId)) {
139 log.info("CCVPN Evaluator Output: service {} is not under closed loop assurance", cllId);
142 if (isServiceUnderMaintenance(cllId)) {
144 log.info("CCVPN Evaluator Output: service {}," +
145 " is in maintenance state, fetching bandwidth info from AAI", cllId);
147 log.info("CCVPN Evaluator Output: candidate {}," +
148 " need an adjustment, but skipped due to in maintenance state", cllId);
150 post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, cllId));
153 //not in the mid of adjustment; we are free to adjust.
154 log.info("CCVPN Evaluator Output: candidate {}," +
155 " need an adjustment, sending request to policy, service state changed to under maintenance", entry.getKey());
156 ccvpnPmDatastore.updateSvcState(entry.getKey(), ServiceState.UNDER_MAINTENANCE);
157 sendModifyRequest(entry.getKey(), newBw, RequestOwner.DCAE);
159 log.debug("=== Processing periodic check complete ===");
160 } else if (event.type() == SimpleEvent.Type.ONDEMAND_CHECK && isOnDemandCheckOn()) {
161 log.info("=== Processing upperbound adjustment request: {} ===", event.time());
162 JsonObject payload = (JsonObject) event.subject();
163 String serviceId = payload.get(SERVICE_INSTANCE_LOCATION_ID).getAsString();
164 int newBandwidth = payload.get(BANDWIDTH_TOTAL).getAsInt();
165 log.info("Update service {} bandwidth upperbound to {} ", serviceId, newBandwidth);
166 ccvpnPmDatastore.updateUpperBoundBw(serviceId, newBandwidth);
167 log.debug("=== Processing upperbound adjustment complete ===");
172 public String getName() {
177 * Post/broadcast event to the BandwidthEvaluator
178 * @param event event object
180 private void post(Event event){
181 bandwidthEvaluator.post(event);
184 private void loadConfig() {
185 configuration = Configuration.getInstance();
186 upperThreshold = configuration.getCcvpnEvalUpperThreshold();
187 lowerThreshold = configuration.getCcvpnEvalLowerThreshold();
188 precision = configuration.getCcvpnEvalPrecision(); // in Mbps;
191 private boolean isPeriodicCheckOn() {
192 configuration = Configuration.getInstance();
193 return configuration.isCcvpnEvalPeriodicCheckOn();
196 private boolean isOnDemandCheckOn() {
197 configuration = Configuration.getInstance();
198 return configuration.isCcvpnEvalOnDemandCheckOn();
201 // send modification requestion
202 private void sendModifyRequest(String cllId, Integer newBandwidth, RequestOwner owner) {
203 log.info("Sending modification request to policy. RequestOwner: {} - Service: {} change to bw: {}",
204 owner, cllId, newBandwidth);
205 policyService.sendOnsetMessageToPolicy(
206 policyService.formPolicyOnsetMessageForCCVPN(cllId, newBandwidth, owner)
210 private boolean needIncrease(String serviceId, double currAvgUsage, int provBw) {
211 log.info("For service {} judge whether to increase, currAvg bw {}, maxBw {}", serviceId, currAvgUsage, provBw);
212 if ( currAvgUsage > upperThreshold * provBw ) {
213 log.info("decide to increase");
219 private boolean needDecrease(String serviceId, double currAvgUsage, int provBw, int originalBw) {
220 log.info("For service {} judge whether to decrease, original bw {}, currAvg bw {}, prov {}", serviceId, originalBw, currAvgUsage, provBw);
221 if( currAvgUsage < lowerThreshold * provBw) {
222 log.info("decide to decrease");
228 // check is service under maintenance
229 private boolean isServiceUnderMaintenance(String serivceId) {
230 return ccvpnPmDatastore.getStatusOfSvc(serivceId) == ServiceState.UNDER_MAINTENANCE;
233 // get a collection of service under maintenance
234 private Map<String, ServiceState> getServicesUnderMaintenance(){
235 return ccvpnPmDatastore.getSvcStatusMap().entrySet()
237 .filter(e -> e.getValue() == ServiceState.UNDER_MAINTENANCE)
238 .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));