summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVijay Venkatesh Kumar <vv770d@att.com>2022-09-21 03:16:45 +0000
committerGerrit Code Review <gerrit@onap.org>2022-09-21 03:16:45 +0000
commitfd42f9337d28ab9d657df9f2f978b6a31cfbd4af (patch)
treeffc6ff171843843f57cdde93419cee55adf63bf7
parent04610eb4713c238509e304c31f2d1cf09a4147dc (diff)
parentf5db5bd223d369a1186c94f43ab642e9c4d69709 (diff)
Merge "[SLICEMS] Add bw decrease logics and enhance runtime config feature"
-rw-r--r--components/slice-analysis-ms/ChangeLog.md10
-rw-r--r--components/slice-analysis-ms/pom.xml3
-rw-r--r--components/slice-analysis-ms/src/main/docker/config/sliceanalysisms/config_all.json3
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/MainThread.java46
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/aai/AaiService.java38
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/controller/ConfigFetchFromCbs.java2
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallback.java17
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/models/Configuration.java40
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ConfigThread.java77
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/BandwidthEvaluator.java8
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastore.java108
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FixedUpperBoundStrategy.java58
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategy.java209
-rw-r--r--components/slice-analysis-ms/src/main/java/org/onap/slice/analysis/ms/utils/SpringContextUtil.java52
-rw-r--r--components/slice-analysis-ms/src/main/resources/logback.xml3
-rw-r--r--components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/AaiEventNotificationCallbackTest.java4
-rw-r--r--components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/dmaap/VesNotificationCallbackTest.java20
-rw-r--r--components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/models/ConfigurationTest.java9
-rw-r--r--components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/CCVPNPmDatastoreTest.java27
-rw-r--r--components/slice-analysis-ms/src/test/java/org/onap/slice/analysis/ms/service/ccvpn/FlexibleThresholdStrategyTest.java69
-rw-r--r--components/slice-analysis-ms/src/test/resources/config_all.json3
21 files changed, 732 insertions, 74 deletions
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 @@
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
- <version>10.0.21</version>
+ <version>9.0.65</version>
</dependency>
<!-- https://mvnrepository.com/artifact/nl.jqno.equalsverifier/equalsverifier -->
<dependency>
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;
@@ -111,6 +114,39 @@ public class AaiService implements AaiInterface {
}
/**
+ * fetch all valid cll instances
+ * @return
+ */
+ public Set<String> fetchAllCllInstances() {
+ globalSubscriberId = "IBNCustomer";
+ subscriptionServiceType = "IBN";
+ String serviceReqUrl = aaiBaseUrl + "/business/customers/customer/" + globalSubscriberId
+ + "/service-subscriptions/service-subscription/" + subscriptionServiceType + "/service-instances";
+ log.info("serviceReqUrl {}", serviceReqUrl);
+ Set<String> cllInstances = new HashSet<>();
+ try {
+ String serviceInstance =
+ restclient.sendGetRequest(serviceReqUrl, new ParameterizedTypeReference<String>() {}).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
*
* @param snssai SNSSAI ID
@@ -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<String> 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<Map<String, Object>>() {
}.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<String> 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<Map<String, Object>>() {}.getType();
+ Type mapType = new TypeToken<Map<String, Object>>() {
+ }.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<List<String>>() {}.getType();
+ Type listType = new TypeToken<List<String>>() {
+ }.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<String, ServiceState> svcStatus = new ConcurrentHashMap<>();
// Provisioned bandwidth of each endpoint
+ @Getter
private final ConcurrentMap<String, Integer> endpointToProvBw = new ConcurrentHashMap<>();
// Max bandwidth (upper-bound) of each endpoint
+ @Getter
private final ConcurrentMap<String, Integer> upperBoundBw = new ConcurrentHashMap<>();
// Current bandwidth usage data list from customers
+ @Getter
private final ConcurrentMap<Endpointkey, EvictingQueue<Integer>> endpointToUsedBw = new ConcurrentHashMap<>();
+ // Original bandwidth of each endpoint
+ @Getter
+ private final ConcurrentMap<String, Integer> endpointToOriginalBw = new ConcurrentHashMap<>();
+ // Assurance Status of each endpoint
+ @Getter
+ private final ConcurrentMap<String, Boolean> closedLoopBwAssuranceStatus = new ConcurrentHashMap<>();
/**
* Given a cllId, return a map between Endpointkey and their corresponding UsedBw Queue.
@@ -88,11 +104,30 @@ 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
*/
@@ -121,6 +156,35 @@ public class CCVPNPmDatastore {
}
/**
+ * 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
* @param bw new bandwidth
@@ -130,6 +194,47 @@ public class CCVPNPmDatastore {
}
/**
+ * Update local service related variables in case cll is deleted.
+ * @param allValidCllInstances
+ */
+ public void updateCllInstances(Set<String> allValidCllInstances){
+ Set<String> 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<Map.Entry<Endpointkey, EvictingQueue<Integer>>> 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<String> filterInvalidCllIds(Set<String> allValidCllInstances, Set<String> currentCllInstances) {
+ Set<String> 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.
* Otherwise override the old value no matter if it exists or not
@@ -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<String, Integer> 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<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> usedBwMap = ccvpnPmDatastore.getUsedBwMap();
+ Map<String, Integer> candidate = new TreeMap<>();
+ for(Map.Entry<Endpointkey, CCVPNPmDatastore.EvictingQueue<Integer>> 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<String , ServiceState> svcUnderMaintenance = getServicesUnderMaintenance();
+ for (Map.Entry<String, ServiceState> entry: svcUnderMaintenance.entrySet()){
+ candidate.putIfAbsent(entry.getKey(), 0);
+ }
+ // fetch the provisioned bandwidth info if underMaintenance; otherwise send modification request
+ for(Map.Entry<String, Integer> 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<String, ServiceState> 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 @@
</layout>
</appender>
- <root level="debug">
+ <root level="info">
<appender-ref ref="CONSOLE"/>
</root>
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<String> 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<String> 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,