diff --git a/pom.xml b/pom.xml
index 7c3634b3f..03b50bade 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,6 +23,7 @@
42.3.1
6.1.7.Final
6.1.7.Final
+ 8.0.1.Final
1.9.9
@@ -154,6 +155,12 @@
hibernate-c3p0
${hibernatecp30-version}
+
+ org.hibernate.validator
+ hibernate-validator
+ ${hibernate-Validator}
+
+
io.micrometer
micrometer-core
diff --git a/src/main/java/com/autotune/Autotune.java b/src/main/java/com/autotune/Autotune.java
index 4905164a0..d364e0cf5 100644
--- a/src/main/java/com/autotune/Autotune.java
+++ b/src/main/java/com/autotune/Autotune.java
@@ -21,7 +21,6 @@
import com.autotune.analyzer.exceptions.MonitoringAgentNotFoundException;
import com.autotune.analyzer.exceptions.MonitoringAgentNotSupportedException;
import com.autotune.database.init.KruizeHibernateUtil;
-import com.autotune.database.service.ExperimentDBService;
import com.autotune.experimentManager.core.ExperimentManager;
import com.autotune.operator.InitializeDeployment;
import com.autotune.operator.KruizeDeploymentInfo;
@@ -34,8 +33,10 @@
import io.prometheus.client.exporter.MetricsServlet;
import io.prometheus.client.hotspot.DefaultExports;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,8 +54,16 @@ public static void main(String[] args) {
ServletContextHandler context = null;
disableServerLogging();
+ // Create a thread pool with the desired number of threads
+ QueuedThreadPool threadPool = new QueuedThreadPool();
+ threadPool.setMaxThreads(KRUIZE_HTTP_THREAD_POOL_COUNT); // Set the maximum number of threads in the pool
+ Server server = new Server(threadPool);
+ // Create a connector (e.g., HTTP)
+ ServerConnector connector = new ServerConnector(server);
+ connector.setPort(KRUIZE_SERVER_PORT);
+ // Set the connector to the server
+ server.addConnector(connector);
- Server server = new Server(KRUIZE_SERVER_PORT);
context = new ServletContextHandler();
context.setContextPath(ServerContext.ROOT_CONTEXT);
context.setErrorHandler(new KruizeErrorHandler());
@@ -74,7 +83,8 @@ public static void main(String[] args) {
try {
InitializeDeployment.setup_deployment_info();
- } catch (Exception | K8sTypeNotSupportedException | MonitoringAgentNotSupportedException | MonitoringAgentNotFoundException e) {
+ } catch (Exception | K8sTypeNotSupportedException | MonitoringAgentNotSupportedException |
+ MonitoringAgentNotFoundException e) {
e.printStackTrace();
System.exit(1);
}
@@ -105,6 +115,7 @@ public static void main(String[] args) {
try {
server.start();
+ server.join();
} catch (Exception e) {
LOGGER.error("Could not start the server!");
e.printStackTrace();
diff --git a/src/main/java/com/autotune/analyzer/exceptions/KruizeErrorHandler.java b/src/main/java/com/autotune/analyzer/exceptions/KruizeErrorHandler.java
index 6561ef938..25780d41e 100644
--- a/src/main/java/com/autotune/analyzer/exceptions/KruizeErrorHandler.java
+++ b/src/main/java/com/autotune/analyzer/exceptions/KruizeErrorHandler.java
@@ -15,6 +15,7 @@
*******************************************************************************/
package com.autotune.analyzer.exceptions;
+import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
import com.google.gson.Gson;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
@@ -23,6 +24,7 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.List;
import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING;
import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE;
@@ -41,9 +43,12 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques
response.setCharacterEncoding(CHARACTER_ENCODING);
String origMessage = (String) request.getAttribute("javax.servlet.error.message");
int errorCode = response.getStatus();
+ List myList = (List) request.getAttribute("data");
+
+
PrintWriter out = response.getWriter();
out.append(
- new Gson().toJson(new KruizeResponse(origMessage, errorCode, "", "ERROR")));
+ new Gson().toJson(new KruizeResponse(origMessage, errorCode, "", "ERROR", myList)));
out.flush();
}
}
diff --git a/src/main/java/com/autotune/analyzer/exceptions/KruizeResponse.java b/src/main/java/com/autotune/analyzer/exceptions/KruizeResponse.java
index 18755f23a..fdd177f5e 100644
--- a/src/main/java/com/autotune/analyzer/exceptions/KruizeResponse.java
+++ b/src/main/java/com/autotune/analyzer/exceptions/KruizeResponse.java
@@ -15,12 +15,19 @@
*******************************************************************************/
package com.autotune.analyzer.exceptions;
+import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
+
+import java.util.List;
+
public class KruizeResponse {
private String message;
private int httpcode;
private String documentationLink;
private String status;
+ private List data;
+
+
public KruizeResponse(String message, int httpcode, String documentationLink, String status) {
this.message = message;
this.httpcode = httpcode;
@@ -28,6 +35,14 @@ public KruizeResponse(String message, int httpcode, String documentationLink, St
this.status = status;
}
+ public KruizeResponse(String message, int httpcode, String documentationLink, String status, List data) {
+ this.message = message;
+ this.httpcode = httpcode;
+ this.documentationLink = documentationLink;
+ this.status = status;
+ this.data = data;
+ }
+
public String getMessage() {
return message;
}
diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java
index 21ee37453..8247c11ba 100644
--- a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java
+++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java
@@ -16,18 +16,28 @@
package com.autotune.analyzer.experiment;
import com.autotune.analyzer.kruizeObject.KruizeObject;
-import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
import com.autotune.analyzer.performanceProfiles.PerformanceProfileInterface.PerfProfileInterface;
+import com.autotune.analyzer.serviceObjects.Converters;
+import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
import com.autotune.analyzer.utils.AnalyzerConstants;
import com.autotune.common.data.ValidationOutputData;
import com.autotune.common.data.result.ExperimentResultData;
+import com.autotune.database.service.ExperimentDBService;
+import com.google.gson.annotations.SerializedName;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import org.hibernate.validator.HibernateValidator;
+import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Field;
import java.sql.Timestamp;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Initiates new experiment data validations and push into queue for worker to
@@ -36,9 +46,10 @@
public class ExperimentInitiator {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentInitiator.class);
+ List successUpdateResultsAPIObjects = new ArrayList<>();
+ List failedUpdateResultsAPIObjects = new ArrayList<>();
private ValidationOutputData validationOutputData;
-
/**
* Initiate Experiment validation
*
@@ -68,36 +79,6 @@ public void validateAndAddNewExperiments(
}
}
- /**
- * @param mainKruizeExperimentMap
- * @param experimentResultDataList
- * @param performanceProfilesMap
- */
- public ValidationOutputData validateAndUpdateResults(
- Map mainKruizeExperimentMap,
- List experimentResultDataList,
- Map performanceProfilesMap) {
- ValidationOutputData validationOutputData = new ValidationOutputData(false, null, null);
- try {
- ExperimentResultValidation experimentResultValidation = new ExperimentResultValidation(mainKruizeExperimentMap, performanceProfilesMap);
- experimentResultValidation.validate(experimentResultDataList, performanceProfilesMap);
- if (experimentResultValidation.isSuccess()) {
- ExperimentInterface experimentInterface = new ExperimentInterfaceImpl();
- experimentInterface.addResultsToLocalStorage(mainKruizeExperimentMap, experimentResultDataList);
- validationOutputData.setSuccess(true);
- } else {
- validationOutputData.setSuccess(false);
- validationOutputData.setMessage("Validation failed: " + experimentResultValidation.getErrorMessage());
- }
- } catch (Exception e) {
- LOGGER.error("Validate and push experiment falied: " + e.getMessage());
- validationOutputData.setSuccess(false);
- validationOutputData.setMessage("Exception occurred while validating the result data: " + e.getMessage());
- validationOutputData.setErrorCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- }
- return validationOutputData;
- }
-
// Generate recommendations and add it to the kruize object
public void generateAndAddRecommendations(KruizeObject kruizeObject, List experimentResultDataList, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception {
if (AnalyzerConstants.PerformanceProfileConstants.perfProfileInstances.containsKey(kruizeObject.getPerformanceProfile())) {
@@ -113,4 +94,71 @@ public void generateAndAddRecommendations(KruizeObject kruizeObject, List updateResultsAPIObjects) {
+ List failedDBObjects = new ArrayList<>();
+ Validator validator = Validation.byProvider(HibernateValidator.class)
+ .configure()
+ .messageInterpolator(new ParameterMessageInterpolator())
+ .failFast(false)
+ .buildValidatorFactory()
+ .getValidator();
+
+ for (UpdateResultsAPIObject object : updateResultsAPIObjects) {
+ Set> violations = validator.validate(object, UpdateResultsAPIObject.FullValidationSequence.class);
+ if (violations.isEmpty()) {
+ successUpdateResultsAPIObjects.add(object);
+ } else {
+ List errorReasons = new ArrayList<>();
+ for (ConstraintViolation violation : violations) {
+ String propertyPath = violation.getPropertyPath().toString();
+ if (null != propertyPath && propertyPath.length() != 0) {
+ errorReasons.add(getSerializedName(propertyPath, UpdateResultsAPIObject.class) + ": " + violation.getMessage());
+ } else {
+ errorReasons.add(violation.getMessage());
+ }
+ }
+ object.setErrorReasons(errorReasons);
+ failedUpdateResultsAPIObjects.add(object);
+ }
+ }
+ List resultDataList = new ArrayList<>();
+ successUpdateResultsAPIObjects.forEach(
+ (successObj) -> {
+ resultDataList.add(Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(successObj));
+ }
+ );
+
+ if (successUpdateResultsAPIObjects.size() > 0) {
+ failedDBObjects = new ExperimentDBService().addResultsToDB(resultDataList);
+ failedUpdateResultsAPIObjects.addAll(failedDBObjects);
+ }
+ }
+
+ public String getSerializedName(String fieldName, Class> targetClass) {
+ Class> currentClass = targetClass;
+ while (currentClass != null) {
+ try {
+ Field field = currentClass.getDeclaredField(fieldName);
+ SerializedName annotation = field.getAnnotation(SerializedName.class);
+ if (annotation != null) {
+ fieldName = annotation.value();
+ }
+ } catch (NoSuchFieldException e) {
+ // Field not found in the current class
+ // Move up to the superclass
+ currentClass = currentClass.getSuperclass();
+ }
+ }
+ return fieldName;
+ }
+
+ public List getSuccessUpdateResultsAPIObjects() {
+ return successUpdateResultsAPIObjects;
+ }
+
+ public List getFailedUpdateResultsAPIObjects() {
+ return failedUpdateResultsAPIObjects;
+ }
+
+
}
diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java
index a9d5ae2d9..4c15404fb 100644
--- a/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java
+++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java
@@ -15,209 +15,17 @@
*******************************************************************************/
package com.autotune.analyzer.experiment;
-import com.autotune.analyzer.kruizeObject.KruizeObject;
-import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
-import com.autotune.analyzer.performanceProfiles.utils.PerformanceProfileUtil;
-import com.autotune.analyzer.utils.AnalyzerConstants;
-import com.autotune.analyzer.utils.AnalyzerErrorConstants;
-import com.autotune.common.data.ValidationOutputData;
-import com.autotune.common.data.result.ExperimentResultData;
-import com.autotune.common.data.result.IntervalResults;
-import com.autotune.database.service.ExperimentDBService;
-import com.autotune.utils.KruizeConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.servlet.http.HttpServletResponse;
-import java.util.List;
-import java.util.Map;
-
/**
* Util class to validate input request related to Experiment Results for metrics collection.
*/
public class ExperimentResultValidation {
private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentResultValidation.class);
- private boolean success;
- private String errorMessage;
- private Map mainKruizeExperimentMAP;
- private Map performanceProfileMap;
-
- public ExperimentResultValidation(Map mainKruizeExperimentMAP, Map performanceProfileMap) {
- this.mainKruizeExperimentMAP = mainKruizeExperimentMAP;
- this.performanceProfileMap = performanceProfileMap;
- }
-
- public void validate(List experimentResultDataList, Map performanceProfilesMap) {
- try {
- boolean proceed = false;
- String errorMsg = "";
- for (ExperimentResultData resultData : experimentResultDataList) {
- String expName = resultData.getExperiment_name();
- if (null != expName && !expName.isEmpty() && null != resultData.getIntervalEndTime() && null != resultData.getIntervalStartTime()) {
- try {
- new ExperimentDBService().loadExperimentFromDBByName(mainKruizeExperimentMAP, expName);
- } catch (Exception e) {
- LOGGER.error("Loading saved experiment {} failed: {} ", expName, e.getMessage());
- }
-
- // Check if there is only one K8sObject in resultData
- if (resultData.getKubernetes_objects().size() > 1) {
- errorMsg = errorMsg.concat(String.format("Bulk Kubernetes Objects are unsupported!"));
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_BAD_REQUEST));
- break;
- }
-
- if (mainKruizeExperimentMAP.containsKey(expName)) {
- KruizeObject kruizeObject = mainKruizeExperimentMAP.get(resultData.getExperiment_name());
- // check if the intervalEndTime is greater than intervalStartTime and interval duration is greater than measurement duration
- IntervalResults intervalResults = new IntervalResults(resultData.getIntervalStartTime(), resultData.getIntervalEndTime());
- Double durationInSeconds = intervalResults.getDuration_in_seconds();
- String measurementDurationInMins = kruizeObject.getTrial_settings().getMeasurement_durationMinutes();
- LOGGER.debug("Duration in seconds = {}", intervalResults.getDuration_in_seconds());
- if (durationInSeconds < 0) {
- errorMsg = errorMsg.concat(AnalyzerErrorConstants.AutotuneObjectErrors.WRONG_TIMESTAMP);
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_BAD_REQUEST));
- break;
- } else {
- Double parsedMeasurementDuration = Double.parseDouble(measurementDurationInMins.substring(0, measurementDurationInMins.length() - 3));
- // Calculate the lower and upper bounds for the acceptable range i.e. +-5 seconds
- double lowerRange = Math.abs((parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) - (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS));
- double upperRange = (parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) + (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS);
- if (!(durationInSeconds >= lowerRange && durationInSeconds <= upperRange)) {
- errorMsg = errorMsg.concat(AnalyzerErrorConstants.AutotuneObjectErrors.MEASUREMENT_DURATION_ERROR);
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_BAD_REQUEST));
- break;
- }
- }
- boolean kubeObjsMisMatch = false;
- // Check if Kubernetes Object Type is matched
- String kubeObjTypeInKruizeObject = kruizeObject.getKubernetes_objects().get(0).getType();
- String kubeObjTypeInResultData = resultData.getKubernetes_objects().get(0).getType();
-
- if (!kubeObjTypeInKruizeObject.equals(kubeObjTypeInResultData)) {
- kubeObjsMisMatch = true;
- errorMsg = errorMsg.concat(
- String.format(
- "Kubernetes Object Types MisMatched. Expected Type: %s, Found: %s in Results for experiment: %s \n",
- kubeObjTypeInKruizeObject,
- kubeObjTypeInResultData,
- expName
- ));
- }
-
- // Check if Kubernetes Object Name is matched
- String kubeObjNameInKruizeObject = kruizeObject.getKubernetes_objects().get(0).getName();
- String kubeObjNameInResultsData = resultData.getKubernetes_objects().get(0).getName();
- if (!kubeObjNameInKruizeObject.equals(kubeObjNameInResultsData)) {
- kubeObjsMisMatch = true;
- errorMsg = errorMsg.concat(
- String.format(
- "Kubernetes Object Names MisMatched. Expected Name: %s, Found: %s in Results for experiment: %s \n",
- kubeObjNameInKruizeObject,
- kubeObjNameInResultsData,
- expName
- ));
- }
-
- // Check if Kubernetes Object NameSpace is matched
- String kubeObjNameSpaceInKruizeObject = kruizeObject.getKubernetes_objects().get(0).getNamespace();
- String kubeObjNameSpaceInResultsData = resultData.getKubernetes_objects().get(0).getNamespace();
-
- if (!kubeObjNameSpaceInKruizeObject.equals(kubeObjNameSpaceInResultsData)) {
- kubeObjsMisMatch = true;
- errorMsg = errorMsg.concat(
- String.format(
- "Kubernetes Object Namespaces MisMatched. Expected Namespace: %s, Found: %s in Results for experiment: %s \n",
- kubeObjNameSpaceInKruizeObject,
- kubeObjNameSpaceInResultsData,
- expName
- ));
- }
-
- if (kubeObjsMisMatch) {
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_BAD_REQUEST));
- break;
- }
- /*
- Fetch the performance profile from the Map corresponding to the name in the kruize object,
- and then validate the Performance Profile data
- */
- try {
- LOGGER.debug("Kruize Object: {}", kruizeObject);
- // fetch the Performance Profile from the DB
- try {
- new ExperimentDBService().loadPerformanceProfileFromDBByName(performanceProfilesMap, kruizeObject.getPerformanceProfile());
- } catch (Exception e) {
- LOGGER.error("Loading saved Performance Profile {} failed: {} ", expName, e.getMessage());
- }
- PerformanceProfile performanceProfile = performanceProfilesMap.get(kruizeObject.getPerformanceProfile());
- // validate the 'resultdata' with the performance profile
- errorMsg = PerformanceProfileUtil.validateResults(performanceProfile, resultData);
- if (null == errorMsg || errorMsg.isEmpty()) {
- proceed = true;
- } else {
- proceed = false;
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_BAD_REQUEST));
- break;
- }
- } catch (Exception e) {
- LOGGER.error("Caught Exception: {}", e);
- errorMsg = "Validation failed: " + e.getMessage();
- proceed = false;
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
- break;
- }
- } else {
- proceed = false;
- errorMsg = errorMsg.concat(String.format("Experiment name: %s not found", resultData.getExperiment_name()));
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_BAD_REQUEST));
- break;
- }
- resultData.setValidationOutputData(new ValidationOutputData(true, AnalyzerConstants.ServiceConstants.RESULT_SAVED, HttpServletResponse.SC_CREATED));
- } else {
- errorMsg = errorMsg.concat("experiment_name and timestamp are mandatory fields and they cannot be empty");
- proceed = false;
- resultData.setValidationOutputData(new ValidationOutputData(false, errorMsg, HttpServletResponse.SC_BAD_REQUEST));
- break;
- }
- }
- if (proceed)
- setSuccess(true);
- else
- markFailed(errorMsg);
- } catch (Exception e) {
- e.printStackTrace();
- setErrorMessage("Validation failed: " + e.getMessage());
- }
- }
-
- public void markFailed(String message) {
- setSuccess(false);
- setErrorMessage(message);
- }
-
- public boolean isSuccess() {
- return success;
- }
+}
- public void setSuccess(boolean success) {
- this.success = success;
- }
- public String getErrorMessage() {
- return errorMessage;
- }
- public void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- }
- @Override
- public String toString() {
- return "ExperimentResultValidation{" +
- "success=" + success +
- ", errorMessage='" + errorMessage + '\'' +
- '}';
- }
-}
diff --git a/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java b/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java
index 109dc406b..f06d92e91 100644
--- a/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java
+++ b/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java
@@ -107,7 +107,6 @@ public void generateRecommendation(KruizeObject kruizeObject, List kubernetesAPIObjects;
+ private List errorReasons;
+
public Timestamp getStartTimestamp() {
return startTimestamp;
}
@@ -53,6 +76,14 @@ public void setKubernetesObjects(List kubernetesAPIObjects)
this.kubernetesAPIObjects = kubernetesAPIObjects;
}
+ public List getErrorReasons() {
+ return errorReasons;
+ }
+
+ public void setErrorReasons(List errorReasons) {
+ this.errorReasons = errorReasons;
+ }
+
@Override
public String toString() {
return "UpdateResultsAPIObject{" +
@@ -61,4 +92,13 @@ public String toString() {
", kubernetesAPIObjects=" + kubernetesAPIObjects +
'}';
}
+
+ public interface EvaluateRemainingConstraints {
+ }
+
+ @GroupSequence({UpdateResultsAPIObject.class, InitialValidation.class, ExperimentNameExistValidation.class, EvaluateRemainingConstraints.class})
+ public interface FullValidationSequence {
+ }
+
+
}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/CompareDate.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/CompareDate.java
new file mode 100644
index 000000000..14ff5c7b5
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/CompareDate.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.annotators;
+
+
+import com.autotune.analyzer.serviceObjects.verification.validators.CompareDateValidator;
+import com.autotune.analyzer.utils.AnalyzerErrorConstants;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = CompareDateValidator.class)
+@Documented
+public @interface CompareDate {
+ String message() default AnalyzerErrorConstants.AutotuneObjectErrors.WRONG_TIMESTAMP;
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/ExperimentNameExist.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/ExperimentNameExist.java
new file mode 100644
index 000000000..8d0724ecb
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/ExperimentNameExist.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.annotators;
+
+import com.autotune.analyzer.serviceObjects.verification.validators.ExperimentNameExistValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = ExperimentNameExistValidator.class)
+public @interface ExperimentNameExist {
+ String message() default "Data does not match DB records";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/KubernetesElementsCheck.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/KubernetesElementsCheck.java
new file mode 100644
index 000000000..bc1c72983
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/KubernetesElementsCheck.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.annotators;
+
+import com.autotune.analyzer.serviceObjects.verification.validators.KubernetesElementsValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = KubernetesElementsValidator.class)
+public @interface KubernetesElementsCheck {
+ String message() default "Data does not match DB records";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/PerformanceProfileCheck.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/PerformanceProfileCheck.java
new file mode 100644
index 000000000..be562fd09
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/PerformanceProfileCheck.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.annotators;
+
+import com.autotune.analyzer.serviceObjects.verification.validators.PerformanceProfileValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = PerformanceProfileValidator.class)
+@Documented
+public @interface PerformanceProfileCheck {
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/TimeDifferenceCheck.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/TimeDifferenceCheck.java
new file mode 100644
index 000000000..cb3c9c83c
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/TimeDifferenceCheck.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.annotators;
+
+
+import com.autotune.analyzer.serviceObjects.verification.validators.TimeDifferenceValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = TimeDifferenceValidator.class)
+@Documented
+public @interface TimeDifferenceCheck {
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java
new file mode 100644
index 000000000..caef8701e
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.validators;
+
+import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
+import com.autotune.analyzer.serviceObjects.verification.annotators.CompareDate;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class CompareDateValidator implements ConstraintValidator {
+ private static final Logger LOGGER = LoggerFactory.getLogger(CompareDateValidator.class);
+
+ @Override
+ public void initialize(CompareDate constraintAnnotation) {
+ }
+
+ @Override
+ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) {
+ boolean success = false;
+ if (null != updateResultsAPIObject.getStartTimestamp() && null != updateResultsAPIObject.getEndTimestamp()) {
+ int comparisonResult = updateResultsAPIObject.getStartTimestamp().compareTo(updateResultsAPIObject.getEndTimestamp());
+ if (comparisonResult < 0) {
+ success = true;
+ }
+ }
+ return success;
+ }
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java
new file mode 100644
index 000000000..2e9c64e9a
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.validators;
+
+import com.autotune.analyzer.kruizeObject.KruizeObject;
+import com.autotune.analyzer.serviceObjects.verification.annotators.ExperimentNameExist;
+import com.autotune.database.service.ExperimentDBService;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ExperimentNameExistValidator implements ConstraintValidator {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentNameExistValidator.class);
+ static Map mainKruizeExperimentMAP = new HashMap<>();
+
+
+ // You can inject your database access/repository here to fetch the data
+
+ @Override
+ public boolean isValid(String experimentName, ConstraintValidatorContext context) {
+ boolean success = false;
+ String errorMessage = "";
+ if (!mainKruizeExperimentMAP.containsKey(experimentName)) {
+ // Retrieve the data from the database
+ try {
+ new ExperimentDBService().loadExperimentFromDBByName(mainKruizeExperimentMAP, experimentName);
+ } catch (Exception e) {
+ LOGGER.error("Loading saved experiment {} failed: {} ", experimentName, e.getMessage());
+ errorMessage = String.format("failed to load from DB due to %s", e.getMessage());
+ }
+ }
+
+ if (mainKruizeExperimentMAP.containsKey(experimentName)) {
+ success = true;
+ } else {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(String.format("%s not found %s", experimentName, errorMessage))
+ .addPropertyNode("")
+ .addConstraintViolation();
+ }
+ return success;
+ }
+}
+
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/KubernetesElementsValidator.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/KubernetesElementsValidator.java
new file mode 100644
index 000000000..332d53fdb
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/KubernetesElementsValidator.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.validators;
+
+import com.autotune.analyzer.kruizeObject.KruizeObject;
+import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
+import com.autotune.analyzer.serviceObjects.Converters;
+import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
+import com.autotune.analyzer.serviceObjects.verification.annotators.KubernetesElementsCheck;
+import com.autotune.analyzer.services.UpdateResults;
+import com.autotune.common.data.result.ExperimentResultData;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+public class KubernetesElementsValidator implements ConstraintValidator {
+ @Override
+ public void initialize(KubernetesElementsCheck constraintAnnotation) {
+ ConstraintValidator.super.initialize(constraintAnnotation);
+ }
+
+ @Override
+ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) {
+ boolean success = false;
+ try {
+ KruizeObject kruizeObject = ExperimentNameExistValidator.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName());
+ PerformanceProfile performanceProfile = UpdateResults.performanceProfilesMap.get(kruizeObject.getPerformanceProfile());
+ ExperimentResultData resultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject);
+ String expName = kruizeObject.getExperimentName();
+ String errorMsg = "";
+ boolean kubeObjsMisMatch = false;
+
+ // Check if Kubernetes Object Type is matched
+ String kubeObjTypeInKruizeObject = kruizeObject.getKubernetes_objects().get(0).getType();
+ String kubeObjTypeInResultData = resultData.getKubernetes_objects().get(0).getType();
+
+ if (!kubeObjTypeInKruizeObject.equals(kubeObjTypeInResultData)) {
+ kubeObjsMisMatch = true;
+ errorMsg = errorMsg.concat(
+ String.format(
+ "Kubernetes Object Types MisMatched. Expected Type: %s, Found: %s in Results for experiment: %s \n",
+ kubeObjTypeInKruizeObject,
+ kubeObjTypeInResultData,
+ expName
+ ));
+ }
+
+ // Check if Kubernetes Object Name is matched
+ String kubeObjNameInKruizeObject = kruizeObject.getKubernetes_objects().get(0).getName();
+ String kubeObjNameInResultsData = resultData.getKubernetes_objects().get(0).getName();
+
+ if (!kubeObjNameInKruizeObject.equals(kubeObjNameInResultsData)) {
+ kubeObjsMisMatch = true;
+ errorMsg = errorMsg.concat(
+ String.format(
+ "Kubernetes Object Names MisMatched. Expected Name: %s, Found: %s in Results for experiment: %s \n",
+ kubeObjNameInKruizeObject,
+ kubeObjNameInResultsData,
+ expName
+ ));
+ }
+
+ // Check if Kubernetes Object NameSpace is matched
+ String kubeObjNameSpaceInKruizeObject = kruizeObject.getKubernetes_objects().get(0).getNamespace();
+ String kubeObjNameSpaceInResultsData = resultData.getKubernetes_objects().get(0).getNamespace();
+
+ if (!kubeObjNameSpaceInKruizeObject.equals(kubeObjNameSpaceInResultsData)) {
+ kubeObjsMisMatch = true;
+ errorMsg = errorMsg.concat(
+ String.format(
+ "Kubernetes Object Namespaces MisMatched. Expected Namespace: %s, Found: %s in Results for experiment: %s \n",
+ kubeObjNameSpaceInKruizeObject,
+ kubeObjNameSpaceInResultsData,
+ expName
+ ));
+ }
+
+ if (kubeObjsMisMatch) {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(errorMsg)
+ .addPropertyNode("kubernetes_objects ")
+ .addConstraintViolation();
+ } else {
+ success = true;
+ }
+ } catch (Exception e) {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(e.getMessage())
+ .addPropertyNode("Kubernetes Elements")
+ .addConstraintViolation();
+ }
+
+ return success;
+ }
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java
new file mode 100644
index 000000000..676e24563
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.validators;
+
+import com.autotune.analyzer.kruizeObject.KruizeObject;
+import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
+import com.autotune.analyzer.performanceProfiles.utils.PerformanceProfileUtil;
+import com.autotune.analyzer.serviceObjects.Converters;
+import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
+import com.autotune.analyzer.serviceObjects.verification.annotators.PerformanceProfileCheck;
+import com.autotune.analyzer.services.UpdateResults;
+import com.autotune.common.data.result.ExperimentResultData;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class PerformanceProfileValidator implements ConstraintValidator {
+ private static final Logger LOGGER = LoggerFactory.getLogger(PerformanceProfileValidator.class);
+
+ @Override
+ public void initialize(PerformanceProfileCheck constraintAnnotation) {
+ }
+
+ @Override
+ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) {
+ boolean success = false;
+ /*
+ Fetch the performance profile from the Map corresponding to the name in the kruize object,
+ and then validate the Performance Profile data
+ */
+ try {
+ KruizeObject kruizeObject = ExperimentNameExistValidator.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName());
+ Map performanceProfilesMap = new HashMap<>();
+ PerformanceProfile performanceProfile = UpdateResults.performanceProfilesMap.get(kruizeObject.getPerformanceProfile());
+ ExperimentResultData resultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject);
+ // validate the 'resultdata' with the performance profile
+ String errorMsg = PerformanceProfileUtil.validateResults(performanceProfile, resultData);
+ if (null == errorMsg || errorMsg.isEmpty()) {
+ success = true;
+ } else {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(errorMsg)
+ .addPropertyNode("Performance profile")
+ .addConstraintViolation();
+ }
+ } catch (Exception e) {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(e.getMessage())
+ .addPropertyNode("Performance profile")
+ .addConstraintViolation();
+ }
+ return success;
+ }
+}
diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/TimeDifferenceValidator.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/TimeDifferenceValidator.java
new file mode 100644
index 000000000..12a29f960
--- /dev/null
+++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/TimeDifferenceValidator.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, IBM Corporation and others.
+ *
+ * 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.
+ *******************************************************************************/
+package com.autotune.analyzer.serviceObjects.verification.validators;
+
+
+import com.autotune.analyzer.kruizeObject.KruizeObject;
+import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
+import com.autotune.analyzer.serviceObjects.verification.annotators.TimeDifferenceCheck;
+import com.autotune.common.data.result.IntervalResults;
+import com.autotune.utils.KruizeConstants;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class TimeDifferenceValidator implements ConstraintValidator {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TimeDifferenceValidator.class);
+
+ @Override
+ public void initialize(TimeDifferenceCheck constraintAnnotation) {
+ }
+
+ @Override
+ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) {
+ boolean success = false;
+
+ KruizeObject kruizeObject = ExperimentNameExistValidator.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName());
+
+ IntervalResults intervalResults = new IntervalResults(updateResultsAPIObject.getStartTimestamp(), updateResultsAPIObject.getEndTimestamp());
+ Double durationInSeconds = intervalResults.getDuration_in_seconds();
+ String measurementDurationInMins = kruizeObject.getTrial_settings().getMeasurement_durationMinutes();
+ Double parsedMeasurementDuration = Double.parseDouble(measurementDurationInMins.substring(0, measurementDurationInMins.length() - 3));
+ // Calculate the lower and upper bounds for the acceptable range i.e. +-5 seconds
+ double lowerRange = Math.abs((parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) - (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS));
+ double upperRange = (parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) + (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS);
+ if ((durationInSeconds >= lowerRange && durationInSeconds <= upperRange))
+ success = true;
+
+ return success;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/autotune/analyzer/services/PerformanceProfileService.java b/src/main/java/com/autotune/analyzer/services/PerformanceProfileService.java
index 20bf5d1e3..71be6267e 100644
--- a/src/main/java/com/autotune/analyzer/services/PerformanceProfileService.java
+++ b/src/main/java/com/autotune/analyzer/services/PerformanceProfileService.java
@@ -18,14 +18,14 @@
import com.autotune.analyzer.exceptions.InvalidValueException;
import com.autotune.analyzer.exceptions.PerformanceProfileResponse;
-import com.autotune.analyzer.serviceObjects.Converters;
+import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
import com.autotune.analyzer.performanceProfiles.utils.PerformanceProfileUtil;
+import com.autotune.analyzer.serviceObjects.Converters;
+import com.autotune.analyzer.utils.AnalyzerConstants;
+import com.autotune.analyzer.utils.AnalyzerErrorConstants;
import com.autotune.analyzer.utils.GsonUTCDateAdapter;
import com.autotune.common.data.ValidationOutputData;
import com.autotune.common.data.metrics.Metric;
-import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
-import com.autotune.analyzer.utils.AnalyzerConstants;
-import com.autotune.analyzer.utils.AnalyzerErrorConstants;
import com.autotune.database.service.ExperimentDBService;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
@@ -45,7 +45,6 @@
import java.io.Serial;
import java.util.Collection;
import java.util.Date;
-import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -61,11 +60,13 @@ public class PerformanceProfileService extends HttpServlet {
@Serial
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(PerformanceProfileService.class);
-
+ private ConcurrentHashMap performanceProfilesMap;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
+ performanceProfilesMap = (ConcurrentHashMap) getServletContext()
+ .getAttribute(AnalyzerConstants.PerformanceProfileConstants.PERF_PROFILE_MAP);
}
/**
@@ -75,7 +76,6 @@ public void init(ServletConfig config) throws ServletException {
* @param response
* @throws IOException
*/
-
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
@@ -84,21 +84,20 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
PerformanceProfile performanceProfile = Converters.KruizeObjectConverters.convertInputJSONToCreatePerfProfile(inputData);
ValidationOutputData validationOutputData = PerformanceProfileUtil.validateAndAddProfile(performanceProfilesMap, performanceProfile);
if (validationOutputData.isSuccess()) {
- ValidationOutputData addedToDB;
- addedToDB = new ExperimentDBService().addPerformanceProfileToDB(performanceProfile);
+ ValidationOutputData addedToDB = new ExperimentDBService().addPerformanceProfileToDB(performanceProfile);
if (addedToDB.isSuccess()) {
+ performanceProfilesMap.put(performanceProfile.getName(), performanceProfile);
+ getServletContext().setAttribute(AnalyzerConstants.PerformanceProfileConstants.PERF_PROFILE_MAP, performanceProfilesMap);
LOGGER.debug("Added Performance Profile : {} into the DB with version: {}",
performanceProfile.getName(), performanceProfile.getProfile_version());
sendSuccessResponse(response, "Performance Profile : " + performanceProfile.getName() + " created successfully.");
- }
- else {
+ } else {
sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, addedToDB.getMessage());
}
- }
- else
+ } else
sendErrorResponse(response, null, validationOutputData.getErrorCode(), validationOutputData.getMessage());
} catch (Exception e) {
- sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"Validation failed: " + e.getMessage());
+ sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Validation failed: " + e.getMessage());
} catch (InvalidValueException e) {
throw new RuntimeException(e);
}
@@ -106,6 +105,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
/**
* Get List of Performance Profiles
+ *
* @param req
* @param response
* @throws ServletException
@@ -117,7 +117,6 @@ protected void doGet(HttpServletRequest req, HttpServletResponse response) throw
response.setCharacterEncoding(CHARACTER_ENCODING);
response.setStatus(HttpServletResponse.SC_OK);
String gsonStr = "[]";
- Map performanceProfilesMap = new ConcurrentHashMap<>();
// Fetch all profiles from the DB
try {
new ExperimentDBService().loadAllPerformanceProfiles(performanceProfilesMap);
@@ -136,9 +135,10 @@ protected void doGet(HttpServletRequest req, HttpServletResponse response) throw
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass() == Metric.class && (
f.getName().equals("trialSummaryResult")
- || f.getName().equals("cycleDataMap")
- );
+ || f.getName().equals("cycleDataMap")
+ );
}
+
@Override
public boolean shouldSkipClass(Class> aClass) {
return false;
@@ -153,8 +153,10 @@ public boolean shouldSkipClass(Class> aClass) {
response.getWriter().close();
}
- /**TODO: Need to implement
+ /**
+ * TODO: Need to implement
* Update Performance Profile
+ *
* @param req
* @param resp
* @throws ServletException
@@ -165,8 +167,10 @@ protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws Se
super.doPut(req, resp);
}
- /**TODO: Need to implement
+ /**
+ * TODO: Need to implement
* Delete Performance profile
+ *
* @param req
* @param resp
* @throws ServletException
@@ -179,6 +183,7 @@ protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws
/**
* Send success response in case of no errors or exceptions.
+ *
* @param response
* @param message
* @throws IOException
@@ -200,6 +205,7 @@ private void sendSuccessResponse(HttpServletResponse response, String message) t
/**
* Send response containing corresponding error message in case of failures and exceptions
+ *
* @param response
* @param e
* @param httpStatusCode
diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java
index a12cb52bd..13ba9fd22 100644
--- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java
+++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java
@@ -17,7 +17,6 @@
import com.autotune.analyzer.experiment.ExperimentInitiator;
import com.autotune.analyzer.kruizeObject.KruizeObject;
-import com.autotune.analyzer.recommendations.RecommendationConstants;
import com.autotune.analyzer.serviceObjects.ContainerAPIObject;
import com.autotune.analyzer.serviceObjects.Converters;
import com.autotune.analyzer.serviceObjects.ListRecommendationsAPIObject;
@@ -81,6 +80,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
// Get the values from the request parameters
String experiment_name = request.getParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME);
String intervalEndTimeStr = request.getParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME);
+
String intervalStartTimeStr = request.getParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME);
Timestamp interval_end_time = null;
Timestamp interval_start_time = null;
@@ -96,7 +96,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY);
return;
}
-
if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) {
sendErrorResponse(
response,
@@ -109,6 +108,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr);
}
+
// Check if interval_start_time is provided
if (intervalStartTimeStr != null) {
if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalStartTimeStr)) {
@@ -139,12 +139,11 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
}
LOGGER.debug("experiment_name : {} and interval_start_time : {} and interval_end_time : {} ", experiment_name, intervalStartTimeStr, intervalEndTimeStr);
- List experimentResultDataList = null;
-
+ List experimentResultDataList = null;
+ ExperimentResultData experimentResultData = null;
try {
experimentResultDataList = new ExperimentDBService().getExperimentResultData(experiment_name, interval_start_time, interval_end_time);
-
} catch (Exception e) {
sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
@@ -164,7 +163,9 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
if (validationOutputData.isSuccess())
sendSuccessResponse(response, kruizeObject, interval_end_time);
else {
+
sendErrorResponse(response, null, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, validationOutputData.getMessage());
+
}
} catch (Exception e) {
e.printStackTrace();
@@ -172,11 +173,9 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
experiment_name,
interval_start_time,
interval_end_time);
-
sendErrorResponse(response, null, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
-
}
} else {
sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND);
diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java
index 53d480fd2..a150bae51 100644
--- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java
+++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java
@@ -20,13 +20,11 @@
import com.autotune.analyzer.experiment.ExperimentInitiator;
import com.autotune.analyzer.kruizeObject.KruizeObject;
import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
-import com.autotune.analyzer.serviceObjects.Converters;
import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject;
import com.autotune.analyzer.utils.AnalyzerConstants;
import com.autotune.analyzer.utils.AnalyzerErrorConstants;
-import com.autotune.common.data.ValidationOutputData;
import com.autotune.common.data.result.ExperimentResultData;
-import com.autotune.database.service.ExperimentDBService;
+import com.autotune.operator.KruizeDeploymentInfo;
import com.autotune.utils.MetricsConfig;
import com.google.gson.Gson;
import io.micrometer.core.instrument.Timer;
@@ -41,7 +39,10 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -55,55 +56,43 @@
public class UpdateResults extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(UpdateResults.class);
- private Map performanceProfilesMap = new HashMap<>();
+ public static ConcurrentHashMap performanceProfilesMap;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
- this.performanceProfilesMap = (HashMap) getServletContext()
- .getAttribute(AnalyzerConstants.PerformanceProfileConstants.PERF_PROFILE_MAP);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Timer.Sample timerUpdateResults = Timer.start(MetricsConfig.meterRegistry());
Map mKruizeExperimentMap = new ConcurrentHashMap();
- ;
try {
+ performanceProfilesMap = (ConcurrentHashMap) getServletContext()
+ .getAttribute(AnalyzerConstants.PerformanceProfileConstants.PERF_PROFILE_MAP);
String inputData = request.getReader().lines().collect(Collectors.joining());
List experimentResultDataList = new ArrayList<>();
List updateResultsAPIObjects = Arrays.asList(new Gson().fromJson(inputData, UpdateResultsAPIObject[].class));
// check for bulk entries and respond accordingly
- if (updateResultsAPIObjects.size() > 1) {
- LOGGER.error(AnalyzerErrorConstants.AutotuneObjectErrors.UNSUPPORTED_EXPERIMENT);
- sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.AutotuneObjectErrors.UNSUPPORTED_EXPERIMENT);
+ if (updateResultsAPIObjects.size() > KruizeDeploymentInfo.bulk_update_results_limit) {
+ LOGGER.error(AnalyzerErrorConstants.AutotuneObjectErrors.UNSUPPORTED_EXPERIMENT_RESULTS);
+ sendErrorResponse(request, response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.AutotuneObjectErrors.UNSUPPORTED_EXPERIMENT_RESULTS);
+ return;
+ }
+ ExperimentInitiator experimentInitiator = new ExperimentInitiator();
+ experimentInitiator.validateAndAddExperimentResults(updateResultsAPIObjects);
+ List failureAPIObjs = experimentInitiator.getFailedUpdateResultsAPIObjects();
+ if (failureAPIObjs.size() > 0) {
+ request.setAttribute("data", failureAPIObjs);
+ String errorMessage = String.format("Out of a total of %s records, %s failed to save", updateResultsAPIObjects.size(), failureAPIObjs.size());
+ sendErrorResponse(request, response, null, HttpServletResponse.SC_BAD_REQUEST, errorMessage);
} else {
- for (UpdateResultsAPIObject updateResultsAPIObject : updateResultsAPIObjects) {
- experimentResultDataList.add(Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject));
- }
- ExperimentInitiator experimentInitiator = new ExperimentInitiator();
- ValidationOutputData validationOutputData = experimentInitiator.validateAndUpdateResults(mKruizeExperimentMap, experimentResultDataList, performanceProfilesMap);
- ExperimentResultData invalidKExperimentResultData = experimentResultDataList.stream().filter((rData) -> (!rData.getValidationOutputData().isSuccess())).findAny().orElse(null);
- ValidationOutputData addedToDB = new ValidationOutputData(false, null, null);
- if (null == invalidKExperimentResultData) {
- // TODO savetoDB should move to queue and bulk upload not considered here
- for (ExperimentResultData resultData : experimentResultDataList) {
- addedToDB = new ExperimentDBService().addResultsToDB(resultData);
- if (addedToDB.isSuccess()) {
- sendSuccessResponse(response, AnalyzerConstants.ServiceConstants.RESULT_SAVED);
- } else {
- sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, addedToDB.getMessage());
- }
- }
- } else {
- LOGGER.error("Failed to update results: " + invalidKExperimentResultData.getValidationOutputData().getMessage());
- sendErrorResponse(response, null, invalidKExperimentResultData.getValidationOutputData().getErrorCode(), invalidKExperimentResultData.getValidationOutputData().getMessage());
- }
+ sendSuccessResponse(response, AnalyzerConstants.ServiceConstants.RESULT_SAVED);
}
} catch (Exception e) {
LOGGER.error("Exception: " + e.getMessage());
e.printStackTrace();
- sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+ sendErrorResponse(request, response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
} finally {
if (null != timerUpdateResults) timerUpdateResults.stop(MetricsConfig.timerUpdateResults);
}
@@ -122,7 +111,7 @@ private void sendSuccessResponse(HttpServletResponse response, String message) t
out.flush();
}
- public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws
+ public void sendErrorResponse(HttpServletRequest request, HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws
IOException {
if (null != e) {
LOGGER.error(e.toString());
diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java
index 9cfb57329..7c145bade 100644
--- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java
+++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java
@@ -73,9 +73,12 @@ public static final class AutotuneObjectErrors {
public static final String SLO_REDUNDANCY_ERROR = "SLO Data and Performance Profile cannot exist simultaneously!";
public static final String DUPLICATE_PERF_PROFILE = "Performance Profile already exists: ";
public static final String MISSING_PERF_PROFILE = "Performance Profile doesn't exist : ";
- public static final String UNSUPPORTED_EXPERIMENT = "Bulk entries are currently unsupported!";
+ public static final String UNSUPPORTED_EXPERIMENT = String.format("At present, the system does not support bulk entries!");
+ public static final String UNSUPPORTED_EXPERIMENT_RESULTS = String.format("At present, the system does not support bulk entries exceeding %s in quantity!", KruizeDeploymentInfo.bulk_update_results_limit);
+ public static final String UNSUPPORTED_BULK_KUBERNETES = "Bulk Kubernetes objects are currently unsupported!";
public static final String DUPLICATE_EXPERIMENT = "Experiment name already exists: ";
- public static final String WRONG_TIMESTAMP = "EndTimeStamp cannot be less than StartTimeStamp!";
+ public static final String WRONG_TIMESTAMP = "The Start time should precede the End time!";
+
public static final String MEASUREMENT_DURATION_ERROR = "Interval duration cannot be less than or greater than measurement_duration by more than " + KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS + " seconds";
private AutotuneObjectErrors() {
@@ -129,9 +132,7 @@ public static final class UpdateRecommendationsAPI {
public static final String EXPERIMENT_NAME_MANDATORY = KruizeConstants.JSONKeys.EXPERIMENT_NAME + " is mandatory";
public static final String INTERVAL_END_TIME_MANDATORY = KruizeConstants.JSONKeys.INTERVAL_END_TIME + " is mandatory";
public static final String DATA_NOT_FOUND = "Data not found!";
-
public static final String TIME_COMPARE = "The Start time should precede the End time!";
-
public static final String TIME_GAP_LIMIT = String.format("The gap between the interval_start_time and interval_end_time must be within a maximum of %s days!", KruizeDeploymentInfo.generate_recommendations_date_range_limit_in_days);
private UpdateRecommendationsAPI() {
diff --git a/src/main/java/com/autotune/common/data/metrics/MetricPercentileResults.java b/src/main/java/com/autotune/common/data/metrics/MetricPercentileResults.java
index b66c91e8e..51b44a60a 100644
--- a/src/main/java/com/autotune/common/data/metrics/MetricPercentileResults.java
+++ b/src/main/java/com/autotune/common/data/metrics/MetricPercentileResults.java
@@ -4,15 +4,15 @@
import org.json.JSONObject;
public class MetricPercentileResults {
- private float percentile50;
- private float percentile97;
- private float percentile95;
- private float percentile99;
- private float percentile99Point9;
- private float percentile99Point99;
- private float percentile99Point999;
- private float percentile99Point9999;
- private float percentile100;
+ private Float percentile50;
+ private Float percentile97;
+ private Float percentile95;
+ private Float percentile99;
+ private Float percentile99Point9;
+ private Float percentile99Point99;
+ private Float percentile99Point999;
+ private Float percentile99Point9999;
+ private Float percentile100;
public MetricPercentileResults() {
}
diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java
index 284d24bca..558ea6710 100644
--- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java
+++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java
@@ -19,6 +19,8 @@ public interface ExperimentDAO {
// Add experiment results from local storage to DB and set status to Inprogress
public ValidationOutputData addResultsToDB(KruizeResultsEntry resultsEntry);
+ public List addToDBAndFetchFailedResults(List kruizeResultsEntries);
+
// Add recommendation to DB
public ValidationOutputData addRecommendationToDB(KruizeRecommendationEntry recommendationEntry);
@@ -47,14 +49,17 @@ public interface ExperimentDAO {
List loadExperimentByName(String experimentName) throws Exception;
// Load all results for a particular experimentName
+
List loadResultsByExperimentName(String experimentName, Timestamp interval_start_time, Integer limitRows) throws Exception;
// Load all recommendations of a particular experiment
List loadRecommendationsByExperimentName(String experimentName) throws Exception;
+
// Load a single Performance Profile based on name
List loadPerformanceProfileByName(String performanceProfileName) throws Exception;
+
// Load all recommendations of a particular experiment and interval end Time
KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, Timestamp interval_end_time) throws Exception;
diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java
index 7ee8a6342..51dc6e84c 100644
--- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java
+++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java
@@ -22,8 +22,10 @@
import org.slf4j.LoggerFactory;
import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
import static com.autotune.database.helper.DBConstants.SQLQUERY.*;
@@ -76,9 +78,7 @@ public ValidationOutputData addResultsToDB(KruizeResultsEntry resultsEntry) {
validationOutputData.setMessage(
String.format("A record with the name %s already exists within the timestamp range starting from %s and ending on %s.", resultsEntry.getExperiment_name(), resultsEntry.getInterval_start_time(), resultsEntry.getInterval_end_time())
);
-
} else {
-
throw new Exception(ex.getMessage());
}
} catch (Exception e) {
@@ -97,6 +97,49 @@ public ValidationOutputData addResultsToDB(KruizeResultsEntry resultsEntry) {
return validationOutputData;
}
+ @Override
+ public List addToDBAndFetchFailedResults(List kruizeResultsEntries) {
+ List failedResultsEntries = new ArrayList<>();
+ Transaction tx = null;
+ Timer.Sample timerAddResultsDB = Timer.start(MetricsConfig.meterRegistry());
+ try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) {
+ tx = session.beginTransaction();
+ for (KruizeResultsEntry entry : kruizeResultsEntries) {
+ try {
+ session.merge(entry);
+ } catch (PersistenceException e) {
+ entry.setErrorReasons(List.of(String.format("A record with the name %s already exists within the timestamp range starting from %s and ending on %s.", entry.getExperiment_name(), new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT).format(entry.getInterval_start_time()),
+ new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT).format(entry.getInterval_end_time()))));
+ failedResultsEntries.add(entry);
+ } catch (Exception e) {
+ entry.setErrorReasons(List.of(e.getMessage()));
+ failedResultsEntries.add(entry);
+ }
+ }
+ tx.commit();
+ if (!failedResultsEntries.isEmpty()) {
+ // find elements in kruizeResultsEntries but not in failedResultsEntries
+ List elementsInSuccessOnly = kruizeResultsEntries.stream()
+ .filter(entry -> !failedResultsEntries.contains(entry))
+ .collect(Collectors.toList());
+ tx = session.beginTransaction();
+ for (KruizeResultsEntry entry : elementsInSuccessOnly) {
+ session.merge(entry);
+ }
+ tx.commit();
+ }
+ } catch (Exception e) {
+ LOGGER.error("Not able to save experiment due to {}", e.getMessage());
+ failedResultsEntries.addAll(kruizeResultsEntries);
+ failedResultsEntries.forEach((entry) -> {
+ entry.setErrorReasons(List.of(e.getMessage()));
+ });
+ } finally {
+ if (null != timerAddResultsDB) timerAddResultsDB.stop(MetricsConfig.timerAddResultsDB);
+ }
+ return failedResultsEntries;
+ }
+
@Override
public ValidationOutputData addRecommendationToDB(KruizeRecommendationEntry recommendationEntry) {
ValidationOutputData validationOutputData = new ValidationOutputData(false, null, null);
@@ -335,18 +378,6 @@ public List loadRecommendationsByExperimentName(Strin
}
@Override
- public List loadPerformanceProfileByName(String performanceProfileName) throws Exception {
- List entries = null;
- try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) {
- entries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_PERFORMANCE_PROFILE_BY_NAME, KruizePerformanceProfileEntry.class)
- .setParameter("name", performanceProfileName).list();
- } catch (Exception e) {
- LOGGER.error("Not able to load Performance Profile {} due to {}", performanceProfileName, e.getMessage());
- throw new Exception("Error while loading existing profile from database due to : " + e.getMessage());
- }
- return entries;
- }
-
public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, Timestamp interval_end_time) throws Exception {
KruizeRecommendationEntry recommendationEntries = null;
Timer.Sample timerLoadRecExpName = Timer.start(MetricsConfig.meterRegistry());
@@ -367,6 +398,20 @@ public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(Stri
return recommendationEntries;
}
+
+ public List loadPerformanceProfileByName(String performanceProfileName) throws Exception {
+ List entries = null;
+ try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) {
+ entries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_PERFORMANCE_PROFILE_BY_NAME, KruizePerformanceProfileEntry.class)
+ .setParameter("name", performanceProfileName).list();
+ } catch (Exception e) {
+ LOGGER.error("Not able to load Performance Profile {} due to {}", performanceProfileName, e.getMessage());
+ throw new Exception("Error while loading existing profile from database due to : " + e.getMessage());
+ }
+ return entries;
+ }
+
+
@Override
public List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception {
List kruizeResultsEntryList = new ArrayList<>();
@@ -388,6 +433,8 @@ public List getKruizeResultsEntry(String experiment_name, Ti
.setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name)
.getResultList();
}
+
+
} catch (NoResultException e) {
LOGGER.error("Data not found in kruizeResultsEntry for exp_name:{} interval_end_time:{} ", experiment_name, interval_end_time);
kruizeResultsEntryList = null;
@@ -397,5 +444,6 @@ public List getKruizeResultsEntry(String experiment_name, Ti
throw new Exception("Error while loading results from the database due to : " + e.getMessage());
}
return kruizeResultsEntryList;
+
}
}
diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java
index 0ac9a4a95..a949b21e2 100644
--- a/src/main/java/com/autotune/database/helper/DBConstants.java
+++ b/src/main/java/com/autotune/database/helper/DBConstants.java
@@ -10,12 +10,12 @@ public static final class SQLQUERY {
public static final String SELECT_FROM_RESULTS = "from KruizeResultsEntry";
public static final String SELECT_FROM_RESULTS_BY_EXP_NAME = "from KruizeResultsEntry k WHERE k.experiment_name = :experimentName";
public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_end_time <= :%s ORDER BY k.interval_end_time DESC", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME, KruizeConstants.JSONKeys.INTERVAL_START_TIME);
+ public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_START_END_TIME = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_start_time >= :%s and k.interval_end_time <= :%s", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_START_TIME, KruizeConstants.JSONKeys.INTERVAL_END_TIME);
public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_end_time = :%s", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME);
public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_MAX_END_TIME = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_end_time = (SELECT MAX(e.interval_end_time) FROM KruizeResultsEntry e where e.experiment_name = :%s )", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME);
public static final String SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME = "from KruizeRecommendationEntry k WHERE k.experiment_name = :experimentName";
public static final String SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME_AND_END_TIME = String.format("from KruizeRecommendationEntry k WHERE k.experiment_name = :%s and k.interval_end_time= :%s", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME);
public static final String SELECT_FROM_RECOMMENDATIONS = "from KruizeRecommendationEntry";
- public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_START_END_TIME = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_start_time >= :%s and k.interval_end_time <= :%s", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_START_TIME, KruizeConstants.JSONKeys.INTERVAL_END_TIME);
public static final String SELECT_FROM_PERFORMANCE_PROFILE = "from KruizePerformanceProfileEntry";
public static final String SELECT_FROM_PERFORMANCE_PROFILE_BY_NAME = "from KruizePerformanceProfileEntry k WHERE k.name = :name";
public static final String DELETE_FROM_EXPERIMENTS_BY_EXP_NAME = "DELETE FROM KruizeExperimentEntry k WHERE k.experiment_name = :experimentName";
diff --git a/src/main/java/com/autotune/database/helper/DBHelpers.java b/src/main/java/com/autotune/database/helper/DBHelpers.java
index c80c223da..cb7c2c3b6 100644
--- a/src/main/java/com/autotune/database/helper/DBHelpers.java
+++ b/src/main/java/com/autotune/database/helper/DBHelpers.java
@@ -491,6 +491,7 @@ public static List convertResultEntryToUpdateResultsAPIO
updateResultsAPIObject.setExperimentName(kruizeResultsEntry.getExperiment_name());
updateResultsAPIObject.setStartTimestamp(kruizeResultsEntry.getInterval_start_time());
updateResultsAPIObject.setEndTimestamp(kruizeResultsEntry.getInterval_end_time());
+ updateResultsAPIObject.setErrorReasons(kruizeResultsEntry.getErrorReasons());
JsonNode extendedDataNode = kruizeResultsEntry.getExtended_data();
JsonNode k8sObjectsNode = extendedDataNode.get(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS);
List k8sObjectList = new ArrayList<>();
diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java
index 3898abb42..c394ac70c 100644
--- a/src/main/java/com/autotune/database/service/ExperimentDBService.java
+++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java
@@ -41,6 +41,7 @@
import java.sql.Timestamp;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -129,19 +130,19 @@ public void loadAllRecommendations(Map mainKruizeExperimen
}
}
-
public void loadAllPerformanceProfiles(Map performanceProfileMap) throws Exception {
- List entries = experimentDAO.loadAllPerformanceProfiles();
- if (null != entries && !entries.isEmpty()) {
- List performanceProfiles = DBHelpers.Converters.KruizeObjectConverters.convertPerformanceProfileEntryToPerformanceProfileObject(entries);
- if (!performanceProfiles.isEmpty()) {
- performanceProfiles.forEach(performanceProfile ->
- PerformanceProfileUtil.addPerformanceProfile(performanceProfileMap, performanceProfile));
+ if (performanceProfileMap.isEmpty()) {
+ List entries = experimentDAO.loadAllPerformanceProfiles();
+ if (null != entries && !entries.isEmpty()) {
+ List performanceProfiles = DBHelpers.Converters.KruizeObjectConverters.convertPerformanceProfileEntryToPerformanceProfileObject(entries);
+ if (!performanceProfiles.isEmpty()) {
+ performanceProfiles.forEach(performanceProfile ->
+ PerformanceProfileUtil.addPerformanceProfile(performanceProfileMap, performanceProfile));
+ }
}
}
}
-
public void loadResultsFromDBByName(Map mainKruizeExperimentMap, String experimentName, Timestamp interval_end_time, Integer limitRows) throws Exception {
ExperimentInterface experimentInterface = new ExperimentInterfaceImpl();
// Load results from the DB and save to local
@@ -201,18 +202,19 @@ public ValidationOutputData addExperimentToDB(CreateExperimentAPIObject createEx
return validationOutputData;
}
- public ValidationOutputData addResultsToDB(ExperimentResultData resultData) {
- ValidationOutputData validationOutputData = new ValidationOutputData(false, null, null);
- KruizeResultsEntry kruizeResultsEntry = DBHelpers.Converters.KruizeObjectConverters.convertExperimentResultToExperimentResultsTable(resultData);
- validationOutputData = experimentDAO.addResultsToDB(kruizeResultsEntry);
- if (validationOutputData.isSuccess())
- resultData.setStatus(AnalyzerConstants.ExperimentStatus.IN_PROGRESS);
- else {
- resultData.setStatus(AnalyzerConstants.ExperimentStatus.FAILED);
+ public List addResultsToDB(List resultDataList) {
+ List kruizeResultsEntryList = new ArrayList<>();
+ List failedUpdateResultsAPIObjects = new ArrayList<>();
+ for (ExperimentResultData resultData : resultDataList) {
+ KruizeResultsEntry kruizeResultsEntry = DBHelpers.Converters.KruizeObjectConverters.convertExperimentResultToExperimentResultsTable(resultData);
+ kruizeResultsEntryList.add(kruizeResultsEntry);
}
- return validationOutputData;
+ List failedResultsEntries = experimentDAO.addToDBAndFetchFailedResults(kruizeResultsEntryList);
+ failedUpdateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(failedResultsEntries);
+ return failedUpdateResultsAPIObjects;
}
+
public ValidationOutputData addRecommendationToDB(Map experimentsMap, List experimentResultDataList) {
ValidationOutputData validationOutputData = new ValidationOutputData(false, "", null);
if (null == experimentResultDataList) {
@@ -221,7 +223,6 @@ public ValidationOutputData addRecommendationToDB(Map expe
if (experimentResultDataList.size() == 0) {
return validationOutputData;
}
-
for (ExperimentResultData experimentResultData : experimentResultDataList) {
// TODO: Log the list of invalid experiments and return the error instead of bailing out completely
if (!experimentsMap.containsKey(experimentResultData.getExperiment_name())) {
@@ -259,7 +260,6 @@ public ValidationOutputData addPerformanceProfileToDB(PerformanceProfile perform
return validationOutputData;
}
-
/*
* This is a Java method that loads all experiments from the database using an experimentDAO object.
* The method then converts the retrieved data into KruizeObject format, adds them to a list,
@@ -344,6 +344,7 @@ public boolean updateExperimentStatus(KruizeObject kruizeObject, AnalyzerConstan
return true;
}
+
public List getExperimentResultData(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception {
List experimentResultDataList = new ArrayList<>();
List kruizeResultsEntryList = experimentDAO.getKruizeResultsEntry(experiment_name, interval_start_time, interval_end_time);
diff --git a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java
index 0f443df35..4fd5c0a60 100644
--- a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java
+++ b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java
@@ -21,6 +21,7 @@
import org.hibernate.type.SqlTypes;
import java.sql.Timestamp;
+import java.util.List;
/**
* This is a Java class named KruizeResultsEntry annotated with JPA annotations.
@@ -47,6 +48,9 @@ public class KruizeResultsEntry {
@JdbcTypeCode(SqlTypes.JSON)
private JsonNode meta_data;
+ @Transient
+ private List errorReasons;
+
public String getExperiment_name() {
return experiment_name;
}
@@ -102,4 +106,12 @@ public String getVersion() {
public void setVersion(String version) {
this.version = version;
}
+
+ public List getErrorReasons() {
+ return errorReasons;
+ }
+
+ public void setErrorReasons(List errorReasons) {
+ this.errorReasons = errorReasons;
+ }
}
diff --git a/src/main/java/com/autotune/operator/InitializeDeployment.java b/src/main/java/com/autotune/operator/InitializeDeployment.java
index b50698407..8dd60dd92 100644
--- a/src/main/java/com/autotune/operator/InitializeDeployment.java
+++ b/src/main/java/com/autotune/operator/InitializeDeployment.java
@@ -105,7 +105,10 @@ private static void setConfigValues(String configFileName, Class envClass) {
deploymentInfoField.set(null, deploymentInfoFieldValue);
else if (deploymentInfoField.getType() == Boolean.class)
deploymentInfoField.set(null, Boolean.parseBoolean(deploymentInfoFieldValue));
- else
+ else if (deploymentInfoField.getType() == Integer.class) {
+ assert deploymentInfoFieldValue != null;
+ deploymentInfoField.set(null, Integer.parseInt(deploymentInfoFieldValue));
+ } else
throw new IllegalAccessException("Failed to set " + deploymentInfoField + "due to its type " + deploymentInfoField.getType());
} catch (Exception e) {
LOGGER.warn("Error while setting config variables : {} : {}", e.getClass(), e.getMessage());
@@ -137,7 +140,7 @@ private static String getKruizeConfigValue(String envName, JSONObject kruizeConf
//Override if env value set outside kruizeConfigJson
String sysEnvValue = System.getenv(envName);
if (null == sysEnvValue && null == envValue) {
- message = message + ", nor not able to set via environment variable and set to null.";
+ message = message + ", nor not able to set via environment variable and set to null or default.";
} else {
if (null != sysEnvValue && envValue == null) {
envValue = sysEnvValue;
diff --git a/src/main/java/com/autotune/operator/KruizeDeploymentInfo.java b/src/main/java/com/autotune/operator/KruizeDeploymentInfo.java
index e1e7b5217..c13cdafba 100644
--- a/src/main/java/com/autotune/operator/KruizeDeploymentInfo.java
+++ b/src/main/java/com/autotune/operator/KruizeDeploymentInfo.java
@@ -65,6 +65,7 @@ public class KruizeDeploymentInfo {
public static String database_ssl_mode;
public static Boolean settings_save_to_db;
public static String em_only_mode;
+ public static Integer bulk_update_results_limit = 100;
public static int generate_recommendations_date_range_limit_in_days = 15;
diff --git a/src/main/java/com/autotune/service/InitiateListener.java b/src/main/java/com/autotune/service/InitiateListener.java
index 1de693c0b..9fff47d27 100644
--- a/src/main/java/com/autotune/service/InitiateListener.java
+++ b/src/main/java/com/autotune/service/InitiateListener.java
@@ -15,11 +15,12 @@
*******************************************************************************/
package com.autotune.service;
-import com.autotune.analyzer.performanceProfiles.PerformanceProfilesDeployment;
+import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
import com.autotune.analyzer.utils.AnalyzerConstants;
import com.autotune.common.parallelengine.executor.KruizeExecutor;
import com.autotune.common.parallelengine.queue.KruizeQueue;
import com.autotune.common.trials.ExperimentTrial;
+import com.autotune.database.service.ExperimentDBService;
import com.autotune.experimentManager.data.ExperimentDetailsMap;
import com.autotune.experimentManager.utils.EMConstants;
import com.autotune.experimentManager.utils.EMConstants.ParallelEngineConfigs;
@@ -31,6 +32,7 @@
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -147,7 +149,13 @@ public void run() {
/*
Kruize Performance Profile configuration
*/
- sce.getServletContext().setAttribute(AnalyzerConstants.PerformanceProfileConstants.PERF_PROFILE_MAP, PerformanceProfilesDeployment.performanceProfilesMap);
+ ConcurrentHashMap performanceProfilesMap = new ConcurrentHashMap<>();
+ try {
+ new ExperimentDBService().loadAllPerformanceProfiles(performanceProfilesMap);
+ } catch (Exception e) {
+ LOGGER.error("Failed to load performance profile: {} ", e.getMessage());
+ }
+ sce.getServletContext().setAttribute(AnalyzerConstants.PerformanceProfileConstants.PERF_PROFILE_MAP, performanceProfilesMap);
}
@Override
diff --git a/src/main/java/com/autotune/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java
index cdb744629..dbd6c7920 100644
--- a/src/main/java/com/autotune/utils/KruizeConstants.java
+++ b/src/main/java/com/autotune/utils/KruizeConstants.java
@@ -244,10 +244,10 @@ private TimeUnitsExt() {
public static class TimeConv {
public static final int NO_OF_MSECS_IN_SEC = 1000;
+ public static final int MEASUREMENT_DURATION_THRESHOLD_SECONDS = 30;
public static int NO_OF_SECONDS_PER_MINUTE = 60;
public static int NO_OF_MINUTES_PER_HOUR = 60;
public static int NO_OF_HOURS_PER_DAY = 24;
- public static int MEASUREMENT_DURATION_THRESHOLD_SECONDS = 30;
private TimeConv() {
}
@@ -377,6 +377,7 @@ private DateFormats() {
* In order to assign values to the static variables of KruizeDeploymentInfo
* using Java reflection, the class variables are utilized, and therefore,
* if any new variables are added, their corresponding declaration is necessary.
+ * Ref InitializeDeployment.setConfigValues(KruizeConstants.CONFIG_FILE, KruizeConstants.DATABASE_ENV_NAME.class);
*/
public static final class DATABASE_ENV_NAME {
public static final String DATABASE_ADMIN_USERNAME = "database_adminusername";
@@ -393,6 +394,7 @@ public static final class DATABASE_ENV_NAME {
* In order to assign values to the static variables of KruizeDeploymentInfo
* using Java reflection, the class variables are utilized, and therefore,
* if any new variables are added, their corresponding declaration is necessary.
+ * Ref InitializeDeployment.setConfigValues(KruizeConstants.CONFIG_FILE, KruizeConstants.KRUIZE_CONFIG_ENV_NAME.class);
*/
public static final class KRUIZE_CONFIG_ENV_NAME {
public static final String K8S_TYPE = "k8stype";
@@ -404,6 +406,7 @@ public static final class KRUIZE_CONFIG_ENV_NAME {
public static final String CLUSTER_TYPE = "clustertype";
public static final String AUTOTUNE_MODE = "autotunemode";
public static final String EM_ONLY_MODE = "emonly";
+ public static final String BULK_UPDATE_RESULTS_LIMIT = "bulkresultslimit";
public static final String SETTINGS_SAVE_TO_DB = "savetodb";
public static final String SETTINGS_DB_DRIVER = "dbdriver";
public static final String SETTINGS_HIBERNATE_DIALECT = "hibernate_dialect";
diff --git a/src/main/java/com/autotune/utils/ServerContext.java b/src/main/java/com/autotune/utils/ServerContext.java
index 63ddf842a..a06ed3c40 100644
--- a/src/main/java/com/autotune/utils/ServerContext.java
+++ b/src/main/java/com/autotune/utils/ServerContext.java
@@ -22,6 +22,7 @@
*/
public class ServerContext {
public static final int KRUIZE_SERVER_PORT = Integer.parseInt(System.getenv().getOrDefault("AUTOTUNE_SERVER_PORT", "8080"));
+ public static final int KRUIZE_HTTP_THREAD_POOL_COUNT = Integer.parseInt(System.getenv().getOrDefault("KRUIZE_HTTP_THREAD_POOL_COUNT", "6"));
public static final int HPO_SERVER_PORT = 8085;
// AnalyzerConstants end points
diff --git a/src/main/java/com/autotune/utils/Utils.java b/src/main/java/com/autotune/utils/Utils.java
index f0e493460..2d5e232f7 100644
--- a/src/main/java/com/autotune/utils/Utils.java
+++ b/src/main/java/com/autotune/utils/Utils.java
@@ -237,6 +237,7 @@ public static Timestamp getTimeStampFrom(String format, String date) {
Timestamp convertedDate = Timestamp.from(desiredInstant);
return convertedDate;
+
} catch (Exception e) {
return null;
}