From f5db5bd223d369a1186c94f43ab642e9c4d69709 Mon Sep 17 00:00:00 2001 From: qingshuting Date: Wed, 14 Sep 2022 12:05:19 +0800 Subject: [SLICEMS] Add bw decrease logics and enhance runtime config feature Add closed loop assurance decrease bw logics. Add a thread transfers latest data from cbs client configs to corresponding value. Add runtime configuration function. Fix the bug that cll service info didn't get updated when a cll service is deleted. Issue-ID: DCAEGEN2-3240 Issue-ID: DCAEGEN2-3264 Issue-ID: DCAEGEN2-3255 Issue-ID: DCAEGEN2-3238 Signed-off-by: qingshuting Change-Id: Id611d10973fca1e1715e9e220819dfcf51bbd1ba --- components/slice-analysis-ms/ChangeLog.md | 10 +- components/slice-analysis-ms/pom.xml | 3 +- .../docker/config/sliceanalysisms/config_all.json | 3 +- .../org/onap/slice/analysis/ms/MainThread.java | 46 ++--- .../org/onap/slice/analysis/ms/aai/AaiService.java | 38 +++- .../analysis/ms/controller/ConfigFetchFromCbs.java | 2 +- .../analysis/ms/dmaap/VesNotificationCallback.java | 17 +- .../slice/analysis/ms/models/Configuration.java | 40 ++-- .../slice/analysis/ms/service/ConfigThread.java | 77 ++++++++ .../ms/service/ccvpn/BandwidthEvaluator.java | 8 +- .../ms/service/ccvpn/CCVPNPmDatastore.java | 108 ++++++++++- .../ms/service/ccvpn/FixedUpperBoundStrategy.java | 58 ++++-- .../service/ccvpn/FlexibleThresholdStrategy.java | 209 ++++++++++++++++++++- .../slice/analysis/ms/utils/SpringContextUtil.java | 52 +++++ .../src/main/resources/logback.xml | 3 +- .../ms/dmaap/AaiEventNotificationCallbackTest.java | 4 +- .../ms/dmaap/VesNotificationCallbackTest.java | 20 ++ .../analysis/ms/models/ConfigurationTest.java | 9 +- .../ms/service/ccvpn/CCVPNPmDatastoreTest.java | 27 +++ .../ccvpn/FlexibleThresholdStrategyTest.java | 69 +++++++ .../src/test/resources/config_all.json | 3 +- 21 files changed, 732 insertions(+), 74 deletions(-) create mode 100644 components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java create mode 100644 components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java create mode 100644 components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java diff --git a/components/slice-analysis-ms/ChangeLog.md b/components/slice-analysis-ms/ChangeLog.md index f3152d32..0796670f 100644 --- a/components/slice-analysis-ms/ChangeLog.md +++ b/components/slice-analysis-ms/ChangeLog.md @@ -4,13 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.1.5] - 2022/08/27 +## [1.1.5] - 2022/09/14 - [DCAEGEN2-3221](https://jira.onap.org/browse/DCAEGEN2-3221) - Slice-Analysis-Ms vulnerability updates - [DCAEGEN2-3195](https://jira.onap.org/browse/DCAEGEN2-3195) - CCVPN Kohn Enhancements for Intent-based Cloud Leased Line and Transport Slicing - [DCAEGEN2-3239](https://jira.onap.org/browse/DCAEGEN2-3239) - Enhance BandwidthEvaluator to listen on user's bandwidth threshold + - [DCAEGEN2-3238](https://jira.onap.org/browse/DCAEGEN2-3238) - Enhance BandwidthEvaluator in slice-analysis-ms to support detailed bandwidth adjustment + + - [DCAEGEN2-3255](https://jira.onap.org/browse/DCAEGEN2-3255) - Fix bug of application failed to start + + - [DCAEGEN2-3264](https://jira.onap.org/browse/DCAEGEN2-3264) - Fix bug that cll service instance info didn't get updated when a cll service is deleted + + - [DCAEGEN2-3240](https://jira.onap.org/browse/DCAEGEN2-3240) - Implement runtime service configuration + ## [1.1.4] - 2022/07/28 - [DCAEGEN2-3120](https://jira.onap.org/browse/DCAEGEN2-3120) - Enhance sliceanalysis MS to use DCAE SDK dmaap-client lib diff --git a/components/slice-analysis-ms/pom.xml b/components/slice-analysis-ms/pom.xml index 3b2cfcd7..15ae6ed7 100644 --- a/components/slice-analysis-ms/pom.xml +++ b/components/slice-analysis-ms/pom.xml @@ -7,6 +7,7 @@ * Copyright (C) 2020-2022 Wipro Limited. * Copyright (C) 2022 Huawei Canada Limited. * Copyright (C) 2022 CTC, Inc. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -316,7 +317,7 @@ org.apache.tomcat.embed tomcat-embed-core - 10.0.21 + 9.0.65 diff --git a/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json b/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json index 12e9d08c..9e233536 100644 --- a/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json +++ b/components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json @@ -106,11 +106,12 @@ "sliceanalysisms.aaiNotif.targetSource" : "UUI", "sliceanalysisms.aaiNotif.targetEntity" : "service-instance", "sliceanalysisms.ccvpnEvalInterval": 5, - "sliceanalysisms.ccvpnEvalThreshold": 0.8, "sliceanalysisms.ccvpnEvalPrecision": 100.0, "sliceanalysisms.ccvpnEvalPeriodicCheckOn": true, "sliceanalysisms.ccvpnEvalOnDemandCheckOn": true, "sliceanalysisms.ccvpnEvalStrategy" : "FlexibleThresholdStrategy", + "sliceanalysisms.ccvpnEvalUpperThreshold": 0.8, + "sliceanalysisms.ccvpnEvalLowerThreshold": 0.3, "service_calls": { "policy-req": [] }, diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java index 57a831ea..44566637 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java @@ -1,51 +1,55 @@ /******************************************************************************* * ============LICENSE_START======================================================= - * son-handler + * slice-analysis-ms * ================================================================================ * Copyright (C) 2019-2020 Wipro Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= - * + * *******************************************************************************/ package org.onap.slice.analysis.ms; +import org.onap.slice.analysis.ms.service.ConfigThread; import org.onap.slice.analysis.ms.service.ConsumerThread; import org.onap.slice.analysis.ms.service.PmThread; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** +/** * This class starts the pm thread and consumer thread */ public class MainThread { - private static Logger log = LoggerFactory.getLogger(MainThread.class); - - private MainThread() { - - } - - /** - * main thread initialization. - */ - public static void initiateThreads() { - log.debug("initializing Pm thread & Consumer thread"); - Thread pmThread = new Thread(new PmThread()); - pmThread.start(); - Thread consumerThread = new Thread(new ConsumerThread()); - consumerThread.start(); - } + private static Logger log = LoggerFactory.getLogger(MainThread.class); + + private MainThread() { + + } + + /** + * main thread initialization. + */ + public static void initiateThreads() { + log.debug("initializing Pm thread & Consumer thread"); + Thread pmThread = new Thread(new PmThread()); + pmThread.start(); + Thread consumerThread = new Thread(new ConsumerThread()); + consumerThread.start(); + Thread configThread = new Thread(new ConfigThread()); + configThread.start(); + } } diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java index 9459b64f..b68373d1 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java @@ -4,6 +4,7 @@ * ================================================================================ * Copyright (C) 2021-2022 Wipro Limited. * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +27,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import org.json.JSONArray; import org.json.JSONObject; import org.onap.slice.analysis.ms.models.Configuration; @@ -110,6 +113,39 @@ public class AaiService implements AaiInterface { return responseMap; } + /** + * fetch all valid cll instances + * @return + */ + public Set fetchAllCllInstances() { + globalSubscriberId = "IBNCustomer"; + subscriptionServiceType = "IBN"; + String serviceReqUrl = aaiBaseUrl + "/business/customers/customer/" + globalSubscriberId + + "/service-subscriptions/service-subscription/" + subscriptionServiceType + "/service-instances"; + log.info("serviceReqUrl {}", serviceReqUrl); + Set cllInstances = new HashSet<>(); + try { + String serviceInstance = + restclient.sendGetRequest(serviceReqUrl, new ParameterizedTypeReference() {}).getBody(); + log.debug("The service instance response msg are :{}", serviceInstance); + JSONObject serviceInstanceJson = new JSONObject(serviceInstance); + JSONArray serviceInstanceArray = serviceInstanceJson.getJSONArray("service-instance"); + for (int i = 0; i < serviceInstanceArray.length(); i++) { + JSONObject serviceObj = serviceInstanceArray.getJSONObject(i); + String serviceId = serviceObj.getString("service-instance-id"); + log.debug("Jsonobject {}", serviceObj); + if(serviceId.startsWith("cll")){ + cllInstances.add(serviceId); + log.debug("Add {} to latest service id list", serviceId); + } + } + return cllInstances; + } catch (Exception e) { + log.error("Exception while fetching serviceDetails: " + e); + } + return new HashSet<>(); + } + /** * Fetches the current configuration of a Slice from AAI * @@ -210,7 +246,7 @@ public class AaiService implements AaiInterface { /** * Fetches the SNSSIs of a serviceInstanceId * - * @param serviceInstanceId service instance ID + * @param sliceInstanceId service instance ID * @return snssaiList contains list of SNSSAIs */ public List getSnssaiList(String sliceInstanceId) { diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java index 2bdb0506..e69d45f2 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java @@ -97,8 +97,8 @@ public class ConfigFetchFromCbs implements Runnable { Type mapType = new TypeToken>() { }.getType(); - if (jsonObject.getAsJsonObject("policies") != null) { + log.info("Policy file exist"); if(jsonObject.getAsJsonObject("policies").getAsJsonArray("items").size() == 0) { log.error("No policy in policy drool pdp engine, nothing to update."); } else { diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java index 584da7b7..4b880e3d 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java @@ -3,6 +3,7 @@ * slice-analysis-ms * ================================================================================ * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +22,10 @@ package org.onap.slice.analysis.ms.dmaap; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Set; +import org.onap.slice.analysis.ms.aai.AaiService; import org.onap.slice.analysis.ms.models.Configuration; import org.onap.slice.analysis.ms.models.vesnotification.NotificationFields; @@ -51,6 +53,9 @@ public class VesNotificationCallback implements NotificationCallback { @Autowired CCVPNPmDatastore ccvpnPmDatastore; + @Autowired + AaiService aaiService; + private static Logger log = LoggerFactory.getLogger(VesNotificationCallback.class); /** @@ -86,6 +91,7 @@ public class VesNotificationCallback implements NotificationCallback { String uniId = null; String bw = null; try { + updateCllInstance(); JsonNode node = obj.readTree(msg); JsonNode notificationNode = node.get(EVENT).get(NOTIFICATIONFIELDS); output = obj.treeToValue(notificationNode, NotificationFields.class); @@ -104,11 +110,18 @@ public class VesNotificationCallback implements NotificationCallback { log.error("Error converting VES msg to object, {}", e.getMessage()); } if (cllId != null && uniId != null && bw != null){ - log.info("Saving new CCVPN service usage data into ccvpnPmDatastore"); log.debug("new bandwidth data -- serviceId: {}, uniId: {}, bw: {}", cllId, uniId, bw); ccvpnPmDatastore.addUsedBwToEndpoint(cllId, uniId, bw); } + } + /** + * Get latest services list, and update local related variables. + */ + public void updateCllInstance(){ + Set instances = aaiService.fetchAllCllInstances(); + log.error("instances {}", instances); + ccvpnPmDatastore.updateCllInstances(instances); } } diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java index 4b5fe2ed..c1599517 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java @@ -4,6 +4,7 @@ * ================================================================================ * Copyright (C) 2020-2022 Wipro Limited. * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -69,12 +70,12 @@ public class Configuration { private String rannfnssiDetailsTemplateId; private String desUrl; private int pmDataDurationInWeeks; - private int vesNotifPollingInterval; private String vesNotifChangeIdentifier; private String vesNotifChangeType; private int ccvpnEvalInterval; - private double ccvpnEvalThreshold; + private double ccvpnEvalUpperThreshold; + private double ccvpnEvalLowerThreshold; private double ccvpnEvalPrecision; private String aaiNotifTargetAction; private String aaiNotifTargetSource; @@ -108,15 +109,21 @@ public class Configuration { @Override public String toString() { - return "Configuration [pgHost=" + pgHost + ", pgPort=" + pgPort + ", pgUsername=" + pgUsername + ", pgPassword=" - + pgPassword + ", dmaapServers=" + dmaapServers + ", configDbService=" + configDbService + ", cpsUrl=" - + cpsUrl + ", aaiUrl=" + aaiUrl + ", configDbEnabled=" + configDbEnabled + ", cg=" + cg + ", cid=" + cid - + ", pollingInterval=" + pollingInterval + ", pollingTimeout=" + pollingTimeout + ", aafUsername=" - + aafUsername + ", aafPassword=" + aafPassword + ", streamsSubscribes=" + streamsSubscribes - + ", streamsPublishes=" + streamsPublishes + ", samples=" + samples + ", minPercentageChange=" - + minPercentageChange + ", initialDelaySeconds=" + initialDelaySeconds + ", rannfnssiDetailsTemplateId=" - + rannfnssiDetailsTemplateId + ", desUrl=" + desUrl + ", pmDataDurationInWeeks=" + pmDataDurationInWeeks - + "]"; + return "Configuration [pgHost=" + pgHost + ", pgPort=" + pgPort + ", pgUsername=" + pgUsername + + ", dmaapServers=" + dmaapServers + ", configDbService=" + configDbService + ", cpsUrl=" + + cpsUrl + ", aaiUrl=" + aaiUrl + ", configDbEnabled=" + configDbEnabled + ", cg=" + cg + ", cid=" + cid + + ", pollingInterval=" + pollingInterval + ", pollingTimeout=" + pollingTimeout + ", aafUsername=" + + aafUsername + ", streamsSubscribes=" + streamsSubscribes + + ", streamsPublishes=" + streamsPublishes + ", samples=" + samples + ", minPercentageChange=" + + minPercentageChange + ", initialDelaySeconds=" + initialDelaySeconds + ", rannfnssiDetailsTemplateId=" + + rannfnssiDetailsTemplateId + ", desUrl=" + desUrl + ", pmDataDurationInWeeks=" + pmDataDurationInWeeks + + ", vesNotifPollingInterval=" + vesNotifPollingInterval + ", vesNotifChangeIdentifier=" + + vesNotifChangeIdentifier + ", vesNotifChangeIdentifier=" + vesNotifChangeType + ", ccvpnEvalInterval=" + + ccvpnEvalInterval + ", ccvpnEvalUpperThreshold=" + ccvpnEvalUpperThreshold + ", ccvpnEvalLowerThreshold=" + + ccvpnEvalLowerThreshold + ", ccvpnEvalPrecision=" + ccvpnEvalPrecision + ", aaiNotifTargetAction=" + + aaiNotifTargetAction + ", aaiNotifTargetSource=" + aaiNotifTargetSource + ", aaiNotifTargetEntity=" + + aaiNotifTargetEntity + ", ccvpnEvalPeriodicCheckOn=" + ccvpnEvalPeriodicCheckOn + + ", ccvpnEvalOnDemandCheckOn=" + ccvpnEvalOnDemandCheckOn + ", ccvpnEvalStrategy=" + ccvpnEvalStrategy + "]"; } /** @@ -126,7 +133,8 @@ public class Configuration { log.info("Updating configuration from CBS"); - Type mapType = new TypeToken>() {}.getType(); + Type mapType = new TypeToken>() { + }.getType(); JsonObject subscribes = jsonObject.getAsJsonObject("streams_subscribes"); streamsSubscribes = new Gson().fromJson(subscribes, mapType); @@ -141,7 +149,8 @@ public class Configuration { pgHost = jsonObject.get("postgres.host").getAsString(); JsonArray servers = jsonObject.getAsJsonArray("sliceanalysisms.dmaap.server"); - Type listType = new TypeToken>() {}.getType(); + Type listType = new TypeToken>() { + }.getType(); dmaapServers = new Gson().fromJson(servers, listType); cg = jsonObject.get("sliceanalysisms.cg").getAsString(); @@ -165,7 +174,8 @@ public class Configuration { aaiNotifTargetSource = jsonObject.get("sliceanalysisms.aaiNotif.targetSource").getAsString(); aaiNotifTargetEntity = jsonObject.get("sliceanalysisms.aaiNotif.targetEntity").getAsString(); ccvpnEvalInterval = jsonObject.get("sliceanalysisms.ccvpnEvalInterval").getAsInt(); - ccvpnEvalThreshold = jsonObject.get("sliceanalysisms.ccvpnEvalThreshold").getAsDouble(); + ccvpnEvalUpperThreshold = jsonObject.get("sliceanalysisms.ccvpnEvalUpperThreshold").getAsDouble(); + ccvpnEvalLowerThreshold = jsonObject.get("sliceanalysisms.ccvpnEvalLowerThreshold").getAsDouble(); ccvpnEvalPrecision = jsonObject.get("sliceanalysisms.ccvpnEvalPrecision").getAsDouble(); ccvpnEvalPeriodicCheckOn = jsonObject.get("sliceanalysisms.ccvpnEvalPeriodicCheckOn").getAsBoolean(); ccvpnEvalOnDemandCheckOn = jsonObject.get("sliceanalysisms.ccvpnEvalOnDemandCheckOn").getAsBoolean(); @@ -191,6 +201,6 @@ public class Configuration { } else { cpsUrl = jsonObject.get("sliceanalysisms.cps.url").getAsString(); } - log.info("configuration from CBS {}", this); + log.info("configuration from CBS has been updated to {}", this); } } diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java new file mode 100644 index 00000000..61e445d0 --- /dev/null +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * ============LICENSE_START======================================================= + * slice-analysis-ms + * ================================================================================ + * Copyright (C) 2022 Huawei Technologies Co., Ltd. + * ============================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + *******************************************************************************/ + +package org.onap.slice.analysis.ms.service; + +import org.onap.slice.analysis.ms.models.ConfigPolicy; +import org.onap.slice.analysis.ms.service.ccvpn.CCVPNPmDatastore; +import org.onap.slice.analysis.ms.utils.SpringContextUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This thread is used to convert ccvpn runtime configurations from policy to our local memory CCVPNPmDatastore + */ +public class ConfigThread extends Thread{ + + CCVPNPmDatastore ccvpnPmDatastore = (CCVPNPmDatastore) SpringContextUtil.getBean(CCVPNPmDatastore.class); + private static Logger log = LoggerFactory.getLogger(ConfigThread.class); + + + public ConfigThread () { + super(); + } + + public void run() { + log.info("Config Thread is starting..."); + boolean done = false; + while(!done) { + try { + Thread.sleep(1000); + ConfigPolicy configPolicy = ConfigPolicy.getInstance(); + if(configPolicy != null) { + // config content + String cllId = null; + Boolean clBwAssuranceStatus = null; + int originalBw = 0; + if(configPolicy.getConfig().containsKey("cllId")){ + cllId = String.valueOf(configPolicy.getConfig().get("cllId")); + } + if(configPolicy.getConfig().containsKey("closedLoopStatus")){ + clBwAssuranceStatus = String.valueOf(configPolicy.getConfig().get("closedLoopStatus")).equalsIgnoreCase("true"); + } + if(configPolicy.getConfig().containsKey("originalBw")){ + originalBw = Integer.parseInt(String.valueOf(configPolicy.getConfig().get("originalBw"))); + } + if(cllId!=null && clBwAssuranceStatus!=null){ + ccvpnPmDatastore.updateConfigFromPolicy(cllId, clBwAssuranceStatus, originalBw); + } + } else { + log.debug("Config policy is empty, nothing to update."); + } + + } catch (Exception e) { + log.error("Exception in Config Thread ", e); + done = true; + } + } + } +} diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java index 43391809..7ca100d1 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java @@ -3,6 +3,7 @@ * slice-analysis-ms * ================================================================================ * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,7 +65,6 @@ public class BandwidthEvaluator { private static final Event KILL_PILL = new SimpleEvent(null, 0); private static final int DEFAULT_EVAL_INTERVAL = 5; private static final String DEFAULT_STRATEGY_NAME = "FixedUpperBoundStrategy"; - /** * Interval of each round of evaluation, defined in config_all.json */ @@ -86,6 +86,7 @@ public class BandwidthEvaluator { strategyName = (strategyName != null)? strategyName : DEFAULT_STRATEGY_NAME; evaluationInterval = (evaluationInterval == 0)? DEFAULT_EVAL_INTERVAL : evaluationInterval; EvaluationStrategy strategy = strategyFactory.getStrategy(strategyName); + log.info("{} is utilized as the bandwidth evaluatior strategy", strategyName); /** * Evalution main loop @@ -117,6 +118,7 @@ public class BandwidthEvaluator { log.info("Service modification complete; serviceId: {} with new bandwidth: {}", serviceId, bwValue); ccvpnPmDatastore.updateProvBw(serviceId, bwValue, true); ccvpnPmDatastore.updateSvcState(serviceId, ServiceState.RUNNING); + log.debug("Service state of {} is changed to running", serviceId); } } log.debug("=== Processing AAI network policy query complete ==="); @@ -160,7 +162,7 @@ public class BandwidthEvaluator { * @param event event object */ public void post(@NonNull Event event){ - log.debug("A new event triggered, type: {}, subject: {}, at time: {}", + log.info("A new event triggered, type: {}, subject: {}, at time: {}", event.type(), event.subject(), event.time()); if (event.type() == SimpleEvent.Type.AAI_BW_REQ) { aaiEventLoop.add(event); @@ -171,10 +173,12 @@ public class BandwidthEvaluator { } } + // update configuration private void loadConfig() { configuration = Configuration.getInstance(); evaluationInterval = configuration.getCcvpnEvalInterval(); strategyName = configuration.getCcvpnEvalStrategy(); + log.info("Evaluation loop configs has been loaded. Strategy {}.", strategyName); } /** diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java index 6d9b9604..5f3ce311 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java @@ -3,6 +3,7 @@ * slice-analysis-ms * ================================================================================ * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +21,11 @@ *******************************************************************************/ package org.onap.slice.analysis.ms.service.ccvpn; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import lombok.Getter; +import lombok.Setter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -42,13 +48,23 @@ public class CCVPNPmDatastore { private static Logger log = LoggerFactory.getLogger(CCVPNPmDatastore.class); private static final Pattern pattern = Pattern.compile("([0-9.]+)\\s*(kb|Kb|mb|Mb|Gb|gb)*"); private static final int WINDOW_SIZE = 5; + @Getter private final ConcurrentMap svcStatus = new ConcurrentHashMap<>(); // Provisioned bandwidth of each endpoint + @Getter private final ConcurrentMap endpointToProvBw = new ConcurrentHashMap<>(); // Max bandwidth (upper-bound) of each endpoint + @Getter private final ConcurrentMap upperBoundBw = new ConcurrentHashMap<>(); // Current bandwidth usage data list from customers + @Getter private final ConcurrentMap> endpointToUsedBw = new ConcurrentHashMap<>(); + // Original bandwidth of each endpoint + @Getter + private final ConcurrentMap endpointToOriginalBw = new ConcurrentHashMap<>(); + // Assurance Status of each endpoint + @Getter + private final ConcurrentMap closedLoopBwAssuranceStatus = new ConcurrentHashMap<>(); /** * Given a cllId, return a map between Endpointkey and their corresponding UsedBw Queue. @@ -88,10 +104,29 @@ public class CCVPNPmDatastore { return svcStatus.getOrDefault(cllId, ServiceState.UNKNOWN); } + /** + * If ccvpn flexible threshold is on, then bandwidth can be assured within scope. + * @param cllId + * @return + */ public Integer getUpperBoundBwOfSvc(String cllId){ return upperBoundBw.getOrDefault(cllId, Integer.MAX_VALUE); } + /** + * Get closed loop check status of this cll service + * @param cllId + * @return + */ + public Boolean getClosedloopStatus(String cllId){ + return closedLoopBwAssuranceStatus.getOrDefault(cllId,true); + } + + public int getOriginalBw(String cllId) { + return endpointToOriginalBw.getOrDefault(cllId, 0); + } + + /** * return the complete map of cll service status * @return complete map of serviceStatusMap @@ -120,6 +155,35 @@ public class CCVPNPmDatastore { updateProvBw(cllId, bwvval, false); } + /** + * Update the status, whether close loop bw modification of this cll service is on. + * @param cllId + * @param status + */ + public void updateClosedloopStatus(String cllId, Boolean status){ + closedLoopBwAssuranceStatus.put(cllId, status); + } + + /** + * Update cll original bw, which will not influenced by closed loop bw assurance + * @param cllId + * @param originalBw + */ + public void updateOriginalBw(String cllId, int originalBw){ + endpointToOriginalBw.put(cllId, originalBw); + } + + /** + * Update runtime configurations; + * @param cllId + * @param closedLoopBwAssuranceStatus + * @param originalBw + */ + public void updateConfigFromPolicy(String cllId, Boolean closedLoopBwAssuranceStatus, int originalBw) { + updateClosedloopStatus(cllId, closedLoopBwAssuranceStatus); + updateOriginalBw(cllId, originalBw); + } + /** * Update upper bound bandwidth value to given bandwidth * @param cllId target cll instance id @@ -129,6 +193,47 @@ public class CCVPNPmDatastore { upperBoundBw.put(cllId, bw); } + /** + * Update local service related variables in case cll is deleted. + * @param allValidCllInstances + */ + public void updateCllInstances(Set allValidCllInstances){ + Set invalidCllIds; + invalidCllIds= filterInvalidCllIds(allValidCllInstances, svcStatus.keySet()); + svcStatus.keySet().removeAll(invalidCllIds); + invalidCllIds = filterInvalidCllIds(allValidCllInstances, endpointToProvBw.keySet()); + endpointToProvBw.keySet().removeAll(invalidCllIds); + invalidCllIds = filterInvalidCllIds(allValidCllInstances, upperBoundBw.keySet()); + upperBoundBw.keySet().removeAll(invalidCllIds); + invalidCllIds = filterInvalidCllIds(allValidCllInstances, endpointToOriginalBw.keySet()); + endpointToOriginalBw.keySet().removeAll(invalidCllIds); + invalidCllIds = filterInvalidCllIds(allValidCllInstances, closedLoopBwAssuranceStatus.keySet()); + closedLoopBwAssuranceStatus.keySet().removeAll(invalidCllIds); + for(String invalidCllId : invalidCllIds) { + log.debug("drop {} from endpointToUsedBw", invalidCllId); + endpointToUsedBw.entrySet().stream().dropWhile(map -> map.getKey().getCllId().equalsIgnoreCase(invalidCllId)); + Iterator>> iterator = endpointToUsedBw.entrySet().iterator(); + while(iterator.hasNext()) { + Endpointkey endpointkey = iterator.next().getKey(); + if(endpointkey.getCllId().equalsIgnoreCase(invalidCllId)) { + endpointToUsedBw.remove(endpointkey); + } + } + } + } + + /** + * Filter out cllId to be deleted + * @param allValidCllInstances + * @param currentCllInstances + * @return + */ + public Set filterInvalidCllIds(Set allValidCllInstances, Set currentCllInstances) { + Set invalidCllInstances = new HashSet<>(currentCllInstances); + invalidCllInstances.removeAll(allValidCllInstances); + return invalidCllInstances; + } + /** * Update provisioned bandwidth to given bandwidth value; * if @param{override} is false, only write the bandwidth if it is absent. @@ -141,8 +246,7 @@ public class CCVPNPmDatastore { * @return whether bandwidth value is changed or not. */ public boolean updateProvBw(String cllId, int bw, boolean override){ - if (!override && !endpointToProvBw.containsKey(cllId)){ - endpointToProvBw.put(cllId, bw); + if ( endpointToProvBw.putIfAbsent(cllId, bw) == null || !override){ return true; } else { if (endpointToProvBw.get(cllId) == bw){ diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java index 874e3271..ec864aa0 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java @@ -3,6 +3,7 @@ * slice-analysis-ms * ================================================================================ * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +35,10 @@ import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; +/** + * Threshold strategy can be configured via configuration + * If "sliceanalysisms.ccvpnEvalStrategy" is set to "FixedUpperBoundStrategy", then this class is triggered. + */ @Component public class FixedUpperBoundStrategy implements EvaluationStrategy{ private static Logger log = LoggerFactory.getLogger(FixedUpperBoundStrategy.class); @@ -46,7 +51,7 @@ public class FixedUpperBoundStrategy implements EvaluationStrategy{ /** * Percentage threshold of bandwidth adjustment. */ - private static double threshold; + private static double upperThreshold; /** * Precision of bandwidth evaluation and adjustment. @@ -67,6 +72,11 @@ public class FixedUpperBoundStrategy implements EvaluationStrategy{ loadConfig(); } + /** + * Periodically ensure endpoint bw adjustment is under assurance. + * This method will be invoked when FixedUpperBoundStrategy is set. + * @param event + */ @Override public void execute(Event event){ if (event.type() == SimpleEvent.Type.PERIODIC_CHECK && isPeriodicCheckOn()){ @@ -77,14 +87,18 @@ public class FixedUpperBoundStrategy implements EvaluationStrategy{ String serviceId = entry.getKey().getCllId(); Object[] usedBws = entry.getValue().tryReadToArray(); + if (!ccvpnPmDatastore.getClosedloopStatus(serviceId)) { + log.info("CCVPN Evaluator Output: service {}, closed loop bw modification is off.", serviceId); + continue; + } if (usedBws == null) { // No enough data for evaluating - log.debug("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId); + log.info("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId); continue; } if (ccvpnPmDatastore.getProvBwOfSvc(serviceId) == 0) { // Max bandwidth not cached yet - log.debug("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId); + log.info("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId); post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, serviceId)); continue; } @@ -110,33 +124,39 @@ public class FixedUpperBoundStrategy implements EvaluationStrategy{ // fetch the provisioned bandwidth info if underMaintenance; otherwise send modification request for(Map.Entry entry: candidate.entrySet()) { //still doing adjustment - if (isServiceUnderMaintenance(entry.getKey())) { - if (entry.getValue() == 0){ - log.debug("CCVPN Evaluator Output: service {}," + - " is in maintenance state, fetching bandwidth info from AAI", entry.getKey()); + String cllId = entry.getKey(); + Integer newBw = entry.getValue(); + if(!ccvpnPmDatastore.getClosedloopStatus(cllId)) { + log.info("CCVPN Evaluator Output: service {} is not under closed loop assurance", cllId); + continue; + } + if (isServiceUnderMaintenance(cllId)) { + if (newBw == 0){ + log.info("CCVPN Evaluator Output: service {}," + + " is in maintenance state, fetching bandwidth info from AAI", cllId); } else { - log.debug("CCVPN Evaluator Output: candidate {}," + - " need an adjustment, but skipped due to in maintenance state", entry.getKey()); + log.info("CCVPN Evaluator Output: candidate {}," + + " need an adjustment, but skipped due to in maintenance state", cllId); } - post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, entry.getKey())); + post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, cllId)); continue; } //not in the mid of adjustment; we are free to adjust. log.info("CCVPN Evaluator Output: candidate {}," + - " need an adjustment, sending request to policy", entry.getKey()); + " need an adjustment, sending request to policy", entry.getKey()); ccvpnPmDatastore.updateSvcState(entry.getKey(), ServiceState.UNDER_MAINTENANCE); - sendModifyRequest(entry.getKey(), entry.getValue(), RequestOwner.DCAE); + sendModifyRequest(entry.getKey(), newBw, RequestOwner.DCAE); } log.debug("=== Processing periodic check complete ==="); } if (event.type() == SimpleEvent.Type.ONDEMAND_CHECK && isOnDemandCheckOn()) { - log.debug("=== Processing upperbound adjustment request: {} ===", event.time()); + log.info("=== Processing upperbound adjustment request: {} ===", event.time()); JsonObject payload = (JsonObject) event.subject(); String serviceId = payload.get(SERVICE_INSTANCE_LOCATION_ID).getAsString(); int newBandwidth = payload.get(BANDWIDTH_TOTAL).getAsInt(); log.info("Update service {} bandwidth upperbound to {} ", serviceId, newBandwidth); ccvpnPmDatastore.updateUpperBoundBw(serviceId, newBandwidth); - log.debug("=== Processing upperbound adjustment complete ==="); + log.info("=== Processing upperbound adjustment complete ==="); } } @@ -155,7 +175,7 @@ public class FixedUpperBoundStrategy implements EvaluationStrategy{ private void loadConfig() { configuration = Configuration.getInstance(); - threshold = configuration.getCcvpnEvalThreshold(); + upperThreshold = configuration.getCcvpnEvalUpperThreshold(); precision = configuration.getCcvpnEvalPrecision(); // in Mbps; } @@ -179,9 +199,9 @@ public class FixedUpperBoundStrategy implements EvaluationStrategy{ } // check if an adjustment is necessary private boolean needAdjust(String serivceId, double used, int provBandwidth, int upper){ - log.debug("CCVPN Service Usage Analysis: usage: {}, threshold: {}, currentProvisioned {}, upperbound {}", - used, threshold, provBandwidth, upper); - return provBandwidth > upper || used > threshold * provBandwidth; + log.info("CCVPN Service Usage Analysis: usage: {}, threshold: {}, currentProvisioned {}, upperbound {}", + used, upperThreshold, provBandwidth, upper); + return provBandwidth > upper || used > upperThreshold * provBandwidth; } // calculate new bandwidth to accomodate customer @@ -189,7 +209,7 @@ public class FixedUpperBoundStrategy implements EvaluationStrategy{ if (cur >= upper){ return upper; } - int expected = (int) (Math.ceil((used / threshold) * 1.2 / precision) * precision); + int expected = (int) (Math.ceil((used / upperThreshold) * 1.2 / precision) * precision); return Math.min(expected, upper); } // check is service under maint diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java index d60c3eae..261794c4 100644 --- a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java @@ -3,6 +3,7 @@ * slice-analysis-ms * ================================================================================ * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,18 +21,220 @@ *******************************************************************************/ package org.onap.slice.analysis.ms.service.ccvpn; +import com.google.gson.JsonObject; +import org.onap.slice.analysis.ms.models.Configuration; +import org.onap.slice.analysis.ms.service.PolicyService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.util.Arrays; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; + +/** + * Threshold strategy can be configured via configuration + * If "sliceanalysisms.ccvpnEvalStrategy" is set to "FlexibleThresholdStrategy", then this class is triggered. + */ @Component -public class FlexibleThresholdStrategy implements EvaluationStrategy { +public class FlexibleThresholdStrategy implements EvaluationStrategy{ + private static Logger log = LoggerFactory.getLogger(FixedUpperBoundStrategy.class); + private Configuration configuration; private static final String TYPE_NAME = "FlexibleThresholdStrategy"; + private static final String SERVICE_INSTANCE_LOCATION_ID = "service-instance-location-id"; + private static final String BANDWIDTH_TOTAL = "bandwidth-total"; + + /** + * Percentage threshold of bandwidth increase adjustment. + */ + private static double upperThreshold; + + /** + * Percentage threshold of bandwidth decrease adjustment. + */ + private static double lowerThreshold; + + /** + * Precision of bandwidth evaluation and adjustment. + */ + private static double precision; // in Mbps; + + @Autowired + BandwidthEvaluator bandwidthEvaluator; + + @Autowired + CCVPNPmDatastore ccvpnPmDatastore; + + @Autowired + PolicyService policyService; + + @PostConstruct + public void init() { + loadConfig(); + } + + /** + * Periodically ensure endpoint bw adjustment is under assurance. + * This method will be invoked when FlexibleThresholdStrategy is set. + * @param event + */ @Override - public void execute(Event event) { - return; + public void execute(Event event){ + if (event.type() == SimpleEvent.Type.PERIODIC_CHECK && isPeriodicCheckOn()){ + log.info("=== Processing new periodic check request: {} ===", event.time()); + Map> usedBwMap = ccvpnPmDatastore.getUsedBwMap(); + Map candidate = new TreeMap<>(); + for(Map.Entry> entry: usedBwMap.entrySet()) { + String serviceId = entry.getKey().getCllId(); + Object[] usedBws = entry.getValue().tryReadToArray(); + // Judge whether this cll is under closed loop assurance + if (!ccvpnPmDatastore.getClosedloopStatus(serviceId)) { + log.info("CCVPN Evaluator Output: service {}, closed loop bw modification is off.", serviceId); + continue; + } + if (usedBws == null) { + // Not enough data for evaluating + log.info("CCVPN Evaluator Output: service {}, not enough data to evaluate", serviceId); + continue; + } + if (ccvpnPmDatastore.getProvBwOfSvc(serviceId) == 0) { + // Max bandwidth not cached yet + log.info("CCVPN Evaluator Output: service {}, max bandwidth not cached, wait for next round", serviceId); + post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, serviceId)); + continue; + } + double avg = Arrays.stream(usedBws) + .mapToInt(o -> (int) o) + .summaryStatistics() + .getAverage(); + int provBw = ccvpnPmDatastore.getProvBwOfSvc(serviceId); + int originalBw = ccvpnPmDatastore.getOriginalBw(serviceId); + + if(needIncrease(serviceId, avg, provBw)){ + int newBw = (int) (Math.ceil((avg / upperThreshold) * 1.2 / precision) * precision); + log.info("For cll {}, going to increase bw to {}", serviceId, newBw); + candidate.put(serviceId, Math.max(candidate.getOrDefault(serviceId, 0), newBw)); + } else { + if(needDecrease(serviceId, avg, provBw, originalBw)) { + int newBw = Math.max((int) (Math.ceil(provBw * 0.5)), originalBw); + log.info("For cll {}, going to decrease bw to {}", serviceId, newBw); + candidate.put(serviceId, Math.max(candidate.getOrDefault(serviceId, 0), newBw)); + } + } + } + // check svc under maintenance + Map svcUnderMaintenance = getServicesUnderMaintenance(); + for (Map.Entry entry: svcUnderMaintenance.entrySet()){ + candidate.putIfAbsent(entry.getKey(), 0); + } + // fetch the provisioned bandwidth info if underMaintenance; otherwise send modification request + for(Map.Entry entry: candidate.entrySet()) { + //still doing adjustment + String cllId = entry.getKey(); + Integer newBw = entry.getValue(); + if(!ccvpnPmDatastore.getClosedloopStatus(cllId)) { + log.info("CCVPN Evaluator Output: service {} is not under closed loop assurance", cllId); + continue; + } + if (isServiceUnderMaintenance(cllId)) { + if (newBw == 0){ + log.info("CCVPN Evaluator Output: service {}," + + " is in maintenance state, fetching bandwidth info from AAI", cllId); + } else { + log.info("CCVPN Evaluator Output: candidate {}," + + " need an adjustment, but skipped due to in maintenance state", cllId); + } + post(new SimpleEvent(SimpleEvent.Type.AAI_BW_REQ, cllId)); + continue; + } + //not in the mid of adjustment; we are free to adjust. + log.info("CCVPN Evaluator Output: candidate {}," + + " need an adjustment, sending request to policy, service state changed to under maintenance", entry.getKey()); + ccvpnPmDatastore.updateSvcState(entry.getKey(), ServiceState.UNDER_MAINTENANCE); + sendModifyRequest(entry.getKey(), newBw, RequestOwner.DCAE); + } + log.debug("=== Processing periodic check complete ==="); + } else if (event.type() == SimpleEvent.Type.ONDEMAND_CHECK && isOnDemandCheckOn()) { + log.info("=== Processing upperbound adjustment request: {} ===", event.time()); + JsonObject payload = (JsonObject) event.subject(); + String serviceId = payload.get(SERVICE_INSTANCE_LOCATION_ID).getAsString(); + int newBandwidth = payload.get(BANDWIDTH_TOTAL).getAsInt(); + log.info("Update service {} bandwidth upperbound to {} ", serviceId, newBandwidth); + ccvpnPmDatastore.updateUpperBoundBw(serviceId, newBandwidth); + log.debug("=== Processing upperbound adjustment complete ==="); + } } @Override public String getName() { return TYPE_NAME; } + + /** + * Post/broadcast event to the BandwidthEvaluator + * @param event event object + */ + private void post(Event event){ + bandwidthEvaluator.post(event); + } + + private void loadConfig() { + configuration = Configuration.getInstance(); + upperThreshold = configuration.getCcvpnEvalUpperThreshold(); + lowerThreshold = configuration.getCcvpnEvalLowerThreshold(); + precision = configuration.getCcvpnEvalPrecision(); // in Mbps; + } + + private boolean isPeriodicCheckOn() { + configuration = Configuration.getInstance(); + return configuration.isCcvpnEvalPeriodicCheckOn(); + } + + private boolean isOnDemandCheckOn() { + configuration = Configuration.getInstance(); + return configuration.isCcvpnEvalOnDemandCheckOn(); + } + + // send modification requestion + private void sendModifyRequest(String cllId, Integer newBandwidth, RequestOwner owner) { + log.info("Sending modification request to policy. RequestOwner: {} - Service: {} change to bw: {}", + owner, cllId, newBandwidth); + policyService.sendOnsetMessageToPolicy( + policyService.formPolicyOnsetMessageForCCVPN(cllId, newBandwidth, owner) + ); + } + + private boolean needIncrease(String serviceId, double currAvgUsage, int provBw) { + log.info("For service {} judge whether to increase, currAvg bw {}, maxBw {}", serviceId, currAvgUsage, provBw); + if ( currAvgUsage > upperThreshold * provBw ) { + log.info("decide to increase"); + return true; + } + return false; + } + + private boolean needDecrease(String serviceId, double currAvgUsage, int provBw, int originalBw) { + log.info("For service {} judge whether to decrease, original bw {}, currAvg bw {}, prov {}", serviceId, originalBw, currAvgUsage, provBw); + if( currAvgUsage < lowerThreshold * provBw) { + log.info("decide to decrease"); + return true; + } + return false; + } + + // check is service under maintenance + private boolean isServiceUnderMaintenance(String serivceId) { + return ccvpnPmDatastore.getStatusOfSvc(serivceId) == ServiceState.UNDER_MAINTENANCE; + } + + // get a collection of service under maintenance + private Map getServicesUnderMaintenance(){ + return ccvpnPmDatastore.getSvcStatusMap().entrySet() + .stream() + .filter(e -> e.getValue() == ServiceState.UNDER_MAINTENANCE) + .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue())); + } } diff --git a/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java new file mode 100644 index 00000000..ebe227d2 --- /dev/null +++ b/components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * ============LICENSE_START======================================================= + * slice-analysis-ms + * ================================================================================ + * Copyright (C) 2022 Huawei Technologies Co., Ltd. + * ============================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + *******************************************************************************/ + +package org.onap.slice.analysis.ms.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; + +/** + * This is provided for threads to get bean. + */ +@Configuration +public class SpringContextUtil implements ApplicationContextAware { + private static ApplicationContext applicationContext = null; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringContextUtil.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + public static Object getBean(String beanName) { + return applicationContext.getBean(beanName); + } + + public static Object getBean(Class c) { + return applicationContext.getBean(c); + } +} diff --git a/components/slice-analysis-ms/src/main/resources/logback.xml b/components/slice-analysis-ms/src/main/resources/logback.xml index d727d05d..134c25dc 100644 --- a/components/slice-analysis-ms/src/main/resources/logback.xml +++ b/components/slice-analysis-ms/src/main/resources/logback.xml @@ -7,6 +7,7 @@ * Copyright (C) 2020 Wipro Limited. * Copyright (C) 2022 Huawei Canada Limited. * Copyright (C) 2022 CTC, Inc. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +34,7 @@ - + diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java index 16745193..9fce12f1 100644 --- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java +++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java @@ -4,6 +4,7 @@ * ================================================================================ * Copyright (C) 2022 Huawei Canada Limited. * Copyright (C) 2022 CTC, Inc. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,7 +84,8 @@ public class AaiEventNotificationCallbackTest { jsonObject.addProperty("sliceanalysisms.vesNotifChangeType", "1"); jsonObject.addProperty("sliceanalysisms.vesNotifPollingInterval", "1"); jsonObject.addProperty("sliceanalysisms.ccvpnEvalInterval", "1"); - jsonObject.addProperty("sliceanalysisms.ccvpnEvalThreshold", "1"); + jsonObject.addProperty("sliceanalysisms.ccvpnEvalUpperThreshold", "1"); + jsonObject.addProperty("sliceanalysisms.ccvpnEvalLowerThreshold", "1"); jsonObject.addProperty("sliceanalysisms.ccvpnEvalPrecision", "1"); jsonObject.addProperty("sliceanalysisms.ccvpnEvalPeriodicCheckOn", "1"); jsonObject.addProperty("sliceanalysisms.ccvpnEvalOnDemandCheckOn", "1"); diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java index 74f75a8c..97ee9fa9 100644 --- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java +++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java @@ -4,6 +4,7 @@ * ================================================================================ * Copyright (C) 2020 Wipro Limited. * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,12 +23,20 @@ package org.onap.slice.analysis.ms.dmaap; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashSet; +import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Spy; +import org.onap.slice.analysis.ms.aai.AaiService; +import org.onap.slice.analysis.ms.service.ccvpn.CCVPNPmDatastore; +import org.powermock.api.mockito.PowerMockito; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; import java.io.IOException; @@ -39,6 +48,12 @@ import java.nio.file.Paths; public class VesNotificationCallbackTest { ObjectMapper obj = new ObjectMapper(); + @Mock + AaiService aaiService; + + @Mock + CCVPNPmDatastore ccvpnPmDatastore; + @Spy @InjectMocks VesNotificationCallback vesNotificationCallback; @@ -57,6 +72,11 @@ public class VesNotificationCallbackTest { } catch (IOException e) { e.printStackTrace(); } + Set cllInstances = new HashSet<>(); + cllInstances.add("cll-01"); + cllInstances.add("cll-02"); + Mockito.when(aaiService.fetchAllCllInstances()).thenReturn(cllInstances); + Mockito.doNothing().when(ccvpnPmDatastore).updateCllInstances(Mockito.any()); vesNotificationCallback.activateCallBack(input); Mockito.verify(vesNotificationCallback, Mockito.atLeastOnce()).activateCallBack(Mockito.anyString()); } diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java index 3d9b58d4..78379094 100644 --- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java +++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java @@ -4,6 +4,7 @@ * ================================================================================ * Copyright (C) 2020-2021 Wipro Limited. * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,7 +59,9 @@ public class ConfigurationTest { configuration.setVesNotifChangeType("BandwidthChanged"); configuration.setCcvpnEvalInterval(5); configuration.setCcvpnEvalPrecision(100); - configuration.setCcvpnEvalThreshold(0.8); + configuration.setCcvpnEvalUpperThreshold(0.8); + configuration.setCcvpnEvalLowerThreshold(0.3); + configuration.setCcvpnEvalStrategy("FlexibleThresholdStrategy"); assertEquals(true,configuration.isSecured()); assertEquals("user", configuration.getAafUsername()); assertEquals("password", configuration.getAafPassword()); @@ -85,6 +88,8 @@ public class ConfigurationTest { assertEquals("BandwidthChanged", configuration.getVesNotifChangeType()); assertEquals(5, configuration.getCcvpnEvalInterval()); assertEquals(100.0, configuration.getCcvpnEvalPrecision(), 0.001); - assertEquals(0.8, configuration.getCcvpnEvalThreshold(), 0.001); + assertEquals(0.8, configuration.getCcvpnEvalUpperThreshold(), 0.001); + assertEquals(0.3, configuration.getCcvpnEvalLowerThreshold(), 0.001); + assertEquals("FlexibleThresholdStrategy", configuration.getCcvpnEvalStrategy()); } } diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java index 673ec6a8..8b0b99f3 100644 --- a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java +++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java @@ -3,6 +3,7 @@ * slice-analysis-ms * ================================================================================ * Copyright (C) 2022 Huawei Canada Limited. + * Copyright (C) 2022 Huawei Technologies Co., Ltd. * ============================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +22,8 @@ package org.onap.slice.analysis.ms.service.ccvpn; +import java.util.HashSet; +import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -119,4 +122,28 @@ public class CCVPNPmDatastoreTest { .mapToInt(o -> (int)o) .sum() == 300602 ); } + + @Test + public void updateCllInstancesTest() { + datastore.addUsedBwToEndpoint("cll-01", "uni-n1", "300Mb"); + datastore.updateUpperBoundBw("cll-01", 300); + datastore.updateProvBw("cll-01", "300"); + datastore.updateSvcState("cll-01", ServiceState.RUNNING); + datastore.updateOriginalBw("cll-01", 1000); + datastore.updateClosedloopStatus("cll-01", true); + datastore.addUsedBwToEndpoint("cll-02", "uni-n2", "300Mb"); + datastore.updateUpperBoundBw("cll-02", 300); + datastore.updateProvBw("cll-02", "300"); + datastore.updateSvcState("cll-02", ServiceState.RUNNING); + datastore.updateOriginalBw("cll-02", 1000); + datastore.updateClosedloopStatus("cll-02", true); + Set cllId = new HashSet<>(); + cllId.add("cll-01"); + datastore.updateCllInstances(cllId); + assertEquals(datastore.getEndpointToUsedBw().keySet().size(), 1); + assertEquals(datastore.getUpperBoundBw().keySet().equals(cllId), true); + assertEquals(datastore.getEndpointToProvBw().keySet().equals(cllId), true); + assertEquals(datastore.getSvcStatus().keySet().equals(cllId), true); + assertEquals(datastore.getEndpointToOriginalBw().keySet().equals(cllId), true); + } } diff --git a/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java new file mode 100644 index 00000000..40028923 --- /dev/null +++ b/components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * ============LICENSE_START======================================================= + * slice-analysis-ms + * ================================================================================ + * Copyright (C) 2022 Huawei Technologies Co., Ltd. + * ============================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + *******************************************************************************/ +package org.onap.slice.analysis.ms.service.ccvpn; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = FixedUpperBoundStrategyTest.class) +public class FlexibleThresholdStrategyTest { + + @Spy + @InjectMocks + BandwidthEvaluator bandwidthEvaluator; + + @Spy + @InjectMocks + FlexibleThresholdStrategy flexibleThresholdStrategy; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + @Test + public void initTest() { + flexibleThresholdStrategy.init(); + Mockito.verify(flexibleThresholdStrategy, Mockito.atLeastOnce()).init(); + } + + @Test + public void executeTest() { + Event evt = new SimpleEvent(null, "{}"); + flexibleThresholdStrategy.execute(evt); + Mockito.verify(flexibleThresholdStrategy, Mockito.atLeastOnce()) + .execute(Mockito.any(Event.class)); + } + + @Test + public void getNameTest() { + flexibleThresholdStrategy.getName(); + Mockito.verify(flexibleThresholdStrategy, Mockito.atLeastOnce()).getName(); + } +} diff --git a/components/slice-analysis-ms/src/test/resources/config_all.json b/components/slice-analysis-ms/src/test/resources/config_all.json index f37e438c..fc18cc14 100644 --- a/components/slice-analysis-ms/src/test/resources/config_all.json +++ b/components/slice-analysis-ms/src/test/resources/config_all.json @@ -106,7 +106,8 @@ "sliceanalysisms.aaiNotif.targetSource" : "UUI", "sliceanalysisms.aaiNotif.targetEntity" : "service-instance", "sliceanalysisms.ccvpnEvalInterval": 5, - "sliceanalysisms.ccvpnEvalThreshold": 0.8, + "sliceanalysisms.ccvpnEvalUpperThreshold": 0.8, + "sliceanalysisms.ccvpnEvalLowerThreshold": 0.3, "sliceanalysisms.ccvpnEvalPrecision": 100.0, "sliceanalysisms.ccvpnEvalPeriodicCheckOn": true, "sliceanalysisms.ccvpnEvalOnDemandCheckOn": true, -- cgit 1.2.3-korg