1 /*******************************************************************************
2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2022 Huawei Canada Limited.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ============LICENSE_END=========================================================
20 *******************************************************************************/
21 package org.onap.slice.analysis.ms.service.ccvpn;
23 import com.google.gson.JsonObject;
24 import org.onap.slice.analysis.ms.models.Configuration;
25 import org.onap.slice.analysis.ms.service.PolicyService;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28 import org.springframework.beans.factory.annotation.Autowired;
29 import org.springframework.stereotype.Component;
31 import javax.annotation.PostConstruct;
32 import java.util.Arrays;
34 import java.util.TreeMap;
35 import java.util.stream.Collectors;
38 public class FixedUpperBoundStrategy implements EvaluationStrategy{
39 private static Logger log = LoggerFactory.getLogger(FixedUpperBoundStrategy.class);
40 private Configuration configuration;
42 private static final String TYPE_NAME = "FixedUpperBoundStrategy";
43 private static final String SERVICE_INSTANCE_LOCATION_ID = "service-instance-location-id";
44 private static final String BANDWIDTH_TOTAL = "bandwidth-total";
47 * Percentage threshold of bandwidth adjustment.
49 private static double threshold;
52 * Precision of bandwidth evaluation and adjustment.
54 private static double precision; // in Mbps;
57 BandwidthEvaluator bandwidthEvaluator;
60 CCVPNPmDatastore ccvpnPmDatastore;
63 PolicyService policyService;
71 public void execute(Event event){
72 if (event.type() == SimpleEvent.Type.PERIODIC_CHECK && isPeriodicCheckOn()){
73 log.debug("=== Processing new periodic check request: {} ===", event.time());
74 Map<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> usedBwMap = ccvpnPmDatastore.getUsedBwMap();
75 Map<String, Integer> candidate = new TreeMap<>();
76 for(Map.Entry<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> entry: usedBwMap.entrySet()) {
77 String serviceId = entry.getKey().getCllId();
78 Object[] usedBws = entry.getValue().tryReadToArray();
80 if (usedBws == null) {
81 // No enough data for evaluating
82 log.debug("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId);
85 if (ccvpnPmDatastore.getProvBwOfSvc(serviceId) == 0) {
86 // Max bandwidth not cached yet
87 log.debug("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId);
88 post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, serviceId));
91 double avg = Arrays.stream(usedBws)
92 .mapToInt(o -> (int) o)
95 int provBw = ccvpnPmDatastore.getProvBwOfSvc(serviceId);
96 int upperBw = ccvpnPmDatastore.getUpperBoundBwOfSvc(serviceId);
97 if (needAdjust(serviceId, avg, provBw, upperBw)) {
98 int newBw = needAdjustTo(serviceId, avg, provBw, upperBw);
99 if(Math.abs(newBw - provBw) >= precision){
100 log.info("CCVPN Evaluator Output: service {}, need adjustment, putting into candidate list", serviceId);
101 candidate.put(serviceId, newBw);
105 // check svc under maintenance
106 Map<String , ServiceState> svcUnderMaintenance = getServicesUnderMaintenance();
107 for (Map.Entry<String, ServiceState> entry: svcUnderMaintenance.entrySet()){
108 candidate.putIfAbsent(entry.getKey(), 0);
110 // fetch the provisioned bandwidth info if underMaintenance; otherwise send modification request
111 for(Map.Entry<String, Integer> entry: candidate.entrySet()) {
112 //still doing adjustment
113 if (isServiceUnderMaintenance(entry.getKey())) {
114 if (entry.getValue() == 0){
115 log.debug("CCVPN Evaluator Output: service {}," +
116 " is in maintenance state, fetching bandwidth info from AAI", entry.getKey());
118 log.debug("CCVPN Evaluator Output: candidate {}," +
119 " need an adjustment, but skipped due to in maintenance state", entry.getKey());
121 post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, entry.getKey()));
124 //not in the mid of adjustment; we are free to adjust.
125 log.info("CCVPN Evaluator Output: candidate {}," +
126 " need an adjustment, sending request to policy", entry.getKey());
127 ccvpnPmDatastore.updateSvcState(entry.getKey(), ServiceState.UNDER_MAINTENANCE);
128 sendModifyRequest(entry.getKey(), entry.getValue(), RequestOwner.DCAE);
130 log.debug("=== Processing periodic check complete ===");
132 if (event.type() == SimpleEvent.Type.ONDEMAND_CHECK && isOnDemandCheckOn()) {
133 log.debug("=== Processing upperbound adjustment request: {} ===", event.time());
134 JsonObject payload = (JsonObject) event.subject();
135 String serviceId = payload.get(SERVICE_INSTANCE_LOCATION_ID).getAsString();
136 int newBandwidth = payload.get(BANDWIDTH_TOTAL).getAsInt();
137 log.info("Update service {} bandwidth upperbound to {} ", serviceId, newBandwidth);
138 ccvpnPmDatastore.updateUpperBoundBw(serviceId, newBandwidth);
139 log.debug("=== Processing upperbound adjustment complete ===");
144 public String getName() {
149 * Post/broadcast event to the BandwidthEvaluator
150 * @param event event object
152 private void post(Event event){
153 bandwidthEvaluator.post(event);
156 private void loadConfig() {
157 configuration = Configuration.getInstance();
158 threshold = configuration.getCcvpnEvalThreshold();
159 precision = configuration.getCcvpnEvalPrecision(); // in Mbps;
162 private boolean isPeriodicCheckOn() {
163 configuration = Configuration.getInstance();
164 return configuration.isCcvpnEvalPeriodicCheckOn();
167 private boolean isOnDemandCheckOn() {
168 configuration = Configuration.getInstance();
169 return configuration.isCcvpnEvalOnDemandCheckOn();
172 // send modification requestion
173 private void sendModifyRequest(String cllId, Integer newBandwidth, RequestOwner owner) {
174 log.info("Sending modification request to policy. RequestOwner: {} - Service: {} change to bw: {}",
175 owner, cllId, newBandwidth);
176 policyService.sendOnsetMessageToPolicy(
177 policyService.formPolicyOnsetMessageForCCVPN(cllId, newBandwidth, owner)
180 // check if an adjustment is necessary
181 private boolean needAdjust(String serivceId, double used, int provBandwidth, int upper){
182 log.debug("CCVPN Service Usage Analysis: usage: {}, threshold: {}, currentProvisioned {}, upperbound {}",
183 used, threshold, provBandwidth, upper);
184 return provBandwidth > upper || used > threshold * provBandwidth;
187 // calculate new bandwidth to accomodate customer
188 private int needAdjustTo(String serivceId, double used, int cur, int upper){
192 int expected = (int) (Math.ceil((used / threshold) * 1.2 / precision) * precision);
193 return Math.min(expected, upper);
195 // check is service under maint
196 private boolean isServiceUnderMaintenance(String serivceId) {
197 return ccvpnPmDatastore.getStatusOfSvc(serivceId) == ServiceState.UNDER_MAINTENANCE;
199 // get a collection of service under maint
200 private Map<String, ServiceState> getServicesUnderMaintenance(){
201 return ccvpnPmDatastore.getSvcStatusMap().entrySet()
203 .filter(e -> e.getValue() == ServiceState.UNDER_MAINTENANCE)
204 .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));