From 0410e12fe5a95325bab16f7ed7dc15e13945341a Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 01/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 147 ++++++++++++++++++ .../autotune/database/helper/DBConstants.java | 1 + 2 files changed, 148 insertions(+) create mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java new file mode 100644 index 000000000..b5dbed42f --- /dev/null +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2022 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.services; + +import com.autotune.analyzer.exceptions.KruizeResponse; +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.common.data.result.ContainerData; +import com.autotune.common.data.result.IntervalResults; +import com.autotune.common.k8sObjects.K8sObject; +import com.autotune.database.service.ExperimentDBService; +import com.autotune.utils.KruizeConstants; +import com.autotune.utils.Utils; +import com.google.gson.Gson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.Map; + +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; + +/** + * + */ +@WebServlet(asyncSupported = true) +public class UpdateRecommendation extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // 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); + + // Check if experiment_name is provided + if (experiment_name == null || experiment_name.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); + } + + // Check if interval_end_time is provided + if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); + } + + // Convert interval_endtime to UTC date format + if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { + sendErrorResponse( + response, + new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), + HttpServletResponse.SC_BAD_REQUEST, + String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) + ); + } + + //Check if data exist + Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); + boolean dataExists = false; + try { + dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + } catch (Exception e) { + sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + + if (dataExists) { + //Load KruizeObject and generate recommendation + Map mainKruizeExperimentMAP = new HashMap<>(); + try { + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); + KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { + for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { + for (IntervalResults result : containerData.getResults().values()) { + + } + } + } +// List experimentResultDataList = ; +// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); +// if (!recommendationCheck) +// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", +// experimentResultDataList.get(0).getExperiment_name(), +// experimentResultDataList.get(0).getIntervalEndTime()); +// else { +// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); +// } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); + } + sendSuccessResponse(response, "All ok"); + } + + private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { + response.setContentType(JSON_CONTENT_TYPE); + response.setCharacterEncoding(CHARACTER_ENCODING); + response.setStatus(HttpServletResponse.SC_CREATED); + PrintWriter out = response.getWriter(); + out.append( + new Gson().toJson( + new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") + ) + ); + out.flush(); + } + + public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws + IOException { + if (null != e) { + LOGGER.error(e.toString()); + e.printStackTrace(); + if (null == errorMsg) errorMsg = e.getMessage(); + } + response.sendError(httpStatusCode, errorMsg); + } +} diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index 0ac9a4a95..251f74b02 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -10,6 +10,7 @@ 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"; From 521f1610e19ab1403358ca7ca7b7396129fe5a00 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 14:49:48 +0530 Subject: [PATCH 02/61] Taking care of duplicate entry to recommendation table Signed-off-by: msvinaykumar --- .../database/dao/ExperimentDAOImpl.java | 110 +++++++++++++++--- .../database/service/ExperimentDBService.java | 38 +++--- 2 files changed, 116 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index 7ee8a6342..c618eecad 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,7 @@ public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(Stri return recommendationEntries; } +<<<<<<< HEAD @Override public List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { List kruizeResultsEntryList = new ArrayList<>(); @@ -398,4 +430,54 @@ public List getKruizeResultsEntry(String experiment_name, Ti } return kruizeResultsEntryList; } +======= + + 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<>(); + try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { + + if (interval_start_time != null && interval_end_time != null) { + kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_START_END_TIME, KruizeResultsEntry.class) + .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name) + .setParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME, interval_start_time) + .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) + .getResultList(); + } else if (interval_end_time != null) { + kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME, KruizeResultsEntry.class) + .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name) + .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) + .getResultList(); + } else { + kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_MAX_END_TIME, KruizeResultsEntry.class) + .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; + } catch (Exception e) { + kruizeResultsEntryList = null; + LOGGER.error("Not able to load results due to: {}", e.getMessage()); + throw new Exception("Error while loading results from the database due to : " + e.getMessage()); + } + return kruizeResultsEntryList; + + } +>>>>>>> d35a6510 (Taking care of duplicate entry to recommendation table) } diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 3898abb42..e05cf2d52 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -53,6 +53,7 @@ public ExperimentDBService() { this.experimentDAO = new ExperimentDAOImpl(); } + public void loadAllExperiments(Map mainKruizeExperimentMap) throws Exception { ExperimentInterface experimentInterface = new ExperimentInterfaceImpl(); List entries = experimentDAO.loadAllExperiments(); @@ -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())) { @@ -344,6 +345,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); From a56c5c110882325d11636c3aa29e543e9ddb8e3a Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 23 May 2023 12:51:53 +0530 Subject: [PATCH 03/61] UpdateResults API optimized. Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index c618eecad..60eb49f60 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -17,6 +17,7 @@ import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; +import org.hibernate.exception.ConstraintViolationException; import org.hibernate.query.Query; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From 3ab5e1f421e376783ffb9cc647cc1d789cf141af Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 6 Jun 2023 16:44:42 +0530 Subject: [PATCH 04/61] resolved conflicts Signed-off-by: msvinaykumar --- .../analyzer/services/UpdateResults.java | 55 ++++++++----------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 53d480fd2..6c1a16568 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -26,7 +26,7 @@ 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 +41,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 +58,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 +113,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()); From b152858b82d09f58d0dbfb93dde9d5b69f9bbd6d Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 12 Jun 2023 21:00:27 +0530 Subject: [PATCH 05/61] Moved logic to select results into perfProfiles. Signed-off-by: msvinaykumar --- .../analyzer/services/UpdateRecommendations.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index a12cb52bd..7d955bab7 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -81,6 +81,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 +97,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 +109,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,17 +140,17 @@ 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; } + if (experimentResultDataList.size() > 0) { //Load KruizeObject and generate recommendation @@ -164,7 +165,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 +175,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); From a5c528cf9ad2dfa7916e4e61cd759a326acfaf0d Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 19 Jun 2023 15:58:41 +0530 Subject: [PATCH 06/61] Date range update recommendations are handled Signed-off-by: msvinaykumar --- .../analyzer/services/UpdateRecommendations.java | 3 +++ .../autotune/analyzer/utils/AnalyzerErrorConstants.java | 9 +++++---- .../java/com/autotune/database/dao/ExperimentDAO.java | 2 ++ .../com/autotune/database/dao/ExperimentDAOImpl.java | 1 - .../autotune/database/service/ExperimentDBService.java | 1 - 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index 7d955bab7..a973b16d9 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -81,6 +81,9 @@ 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; String intervalStartTimeStr = request.getParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME); Timestamp interval_end_time = null; 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/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 284d24bca..aa92f3ca1 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); diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index 60eb49f60..c618eecad 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -17,7 +17,6 @@ import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.exception.ConstraintViolationException; import org.hibernate.query.Query; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index e05cf2d52..447169324 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -260,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, From 86ac1d17e394fac959df6c4f78af6900e9c445a4 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 07/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 147 ------------------ 1 file changed, 147 deletions(-) delete mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java deleted file mode 100644 index b5dbed42f..000000000 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ /dev/null @@ -1,147 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022 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.services; - -import com.autotune.analyzer.exceptions.KruizeResponse; -import com.autotune.analyzer.kruizeObject.KruizeObject; -import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ContainerData; -import com.autotune.common.data.result.IntervalResults; -import com.autotune.common.k8sObjects.K8sObject; -import com.autotune.database.service.ExperimentDBService; -import com.autotune.utils.KruizeConstants; -import com.autotune.utils.Utils; -import com.google.gson.Gson; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.sql.Timestamp; -import java.util.HashMap; -import java.util.Map; - -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; - -/** - * - */ -@WebServlet(asyncSupported = true) -public class UpdateRecommendation extends HttpServlet { - private static final long serialVersionUID = 1L; - private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // 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); - - // Check if experiment_name is provided - if (experiment_name == null || experiment_name.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); - } - - // Check if interval_end_time is provided - if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); - } - - // Convert interval_endtime to UTC date format - if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { - sendErrorResponse( - response, - new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), - HttpServletResponse.SC_BAD_REQUEST, - String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) - ); - } - - //Check if data exist - Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); - boolean dataExists = false; - try { - dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); - } catch (Exception e) { - sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - } - - if (dataExists) { - //Load KruizeObject and generate recommendation - Map mainKruizeExperimentMAP = new HashMap<>(); - try { - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { - for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { - for (IntervalResults result : containerData.getResults().values()) { - - } - } - } -// List experimentResultDataList = ; -// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); -// if (!recommendationCheck) -// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", -// experimentResultDataList.get(0).getExperiment_name(), -// experimentResultDataList.get(0).getIntervalEndTime()); -// else { -// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); -// } - } catch (Exception e) { - e.printStackTrace(); - } - } else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); - } - sendSuccessResponse(response, "All ok"); - } - - private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { - response.setContentType(JSON_CONTENT_TYPE); - response.setCharacterEncoding(CHARACTER_ENCODING); - response.setStatus(HttpServletResponse.SC_CREATED); - PrintWriter out = response.getWriter(); - out.append( - new Gson().toJson( - new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") - ) - ); - out.flush(); - } - - public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws - IOException { - if (null != e) { - LOGGER.error(e.toString()); - e.printStackTrace(); - if (null == errorMsg) errorMsg = e.getMessage(); - } - response.sendError(httpStatusCode, errorMsg); - } -} From 7a0b5a75b59148a28d3217b1a1a8047f626e7a45 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 20 Jul 2023 20:44:48 +0530 Subject: [PATCH 08/61] endDate is not mandatory Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/services/UpdateRecommendations.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index a973b16d9..5ade30fad 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,9 +80,6 @@ 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; String intervalStartTimeStr = request.getParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME); Timestamp interval_end_time = null; From 3be9c1be17b75a0907672c77d96f118c53ce26af Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 21 Jul 2023 14:39:38 +0530 Subject: [PATCH 09/61] resolved conflicts Signed-off-by: msvinaykumar --- .../ResourceOptimizationOpenshiftImpl.java | 1 - 1 file changed, 1 deletion(-) 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 Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 10/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 147 ++++++++++++++++++ src/main/java/com/autotune/utils/Utils.java | 1 + 2 files changed, 148 insertions(+) create mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java new file mode 100644 index 000000000..b5dbed42f --- /dev/null +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2022 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.services; + +import com.autotune.analyzer.exceptions.KruizeResponse; +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.common.data.result.ContainerData; +import com.autotune.common.data.result.IntervalResults; +import com.autotune.common.k8sObjects.K8sObject; +import com.autotune.database.service.ExperimentDBService; +import com.autotune.utils.KruizeConstants; +import com.autotune.utils.Utils; +import com.google.gson.Gson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.Map; + +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; + +/** + * + */ +@WebServlet(asyncSupported = true) +public class UpdateRecommendation extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // 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); + + // Check if experiment_name is provided + if (experiment_name == null || experiment_name.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); + } + + // Check if interval_end_time is provided + if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); + } + + // Convert interval_endtime to UTC date format + if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { + sendErrorResponse( + response, + new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), + HttpServletResponse.SC_BAD_REQUEST, + String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) + ); + } + + //Check if data exist + Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); + boolean dataExists = false; + try { + dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + } catch (Exception e) { + sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + + if (dataExists) { + //Load KruizeObject and generate recommendation + Map mainKruizeExperimentMAP = new HashMap<>(); + try { + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); + KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { + for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { + for (IntervalResults result : containerData.getResults().values()) { + + } + } + } +// List experimentResultDataList = ; +// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); +// if (!recommendationCheck) +// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", +// experimentResultDataList.get(0).getExperiment_name(), +// experimentResultDataList.get(0).getIntervalEndTime()); +// else { +// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); +// } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); + } + sendSuccessResponse(response, "All ok"); + } + + private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { + response.setContentType(JSON_CONTENT_TYPE); + response.setCharacterEncoding(CHARACTER_ENCODING); + response.setStatus(HttpServletResponse.SC_CREATED); + PrintWriter out = response.getWriter(); + out.append( + new Gson().toJson( + new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") + ) + ); + out.flush(); + } + + public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws + IOException { + if (null != e) { + LOGGER.error(e.toString()); + e.printStackTrace(); + if (null == errorMsg) errorMsg = e.getMessage(); + } + response.sendError(httpStatusCode, errorMsg); + } +} 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; } From 6581ea074f79ead428c178ba038b86c1ef4e7444 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 14:49:48 +0530 Subject: [PATCH 11/61] Taking care of duplicate entry to recommendation table Signed-off-by: msvinaykumar --- .../java/com/autotune/database/service/ExperimentDBService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 447169324..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; @@ -53,7 +54,6 @@ public ExperimentDBService() { this.experimentDAO = new ExperimentDAOImpl(); } - public void loadAllExperiments(Map mainKruizeExperimentMap) throws Exception { ExperimentInterface experimentInterface = new ExperimentInterfaceImpl(); List entries = experimentDAO.loadAllExperiments(); From 79fac3c9ad91af3ffdb99762ef867fa8ec228cf4 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 12/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 147 ------------------ 1 file changed, 147 deletions(-) delete mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java deleted file mode 100644 index b5dbed42f..000000000 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ /dev/null @@ -1,147 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022 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.services; - -import com.autotune.analyzer.exceptions.KruizeResponse; -import com.autotune.analyzer.kruizeObject.KruizeObject; -import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ContainerData; -import com.autotune.common.data.result.IntervalResults; -import com.autotune.common.k8sObjects.K8sObject; -import com.autotune.database.service.ExperimentDBService; -import com.autotune.utils.KruizeConstants; -import com.autotune.utils.Utils; -import com.google.gson.Gson; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.sql.Timestamp; -import java.util.HashMap; -import java.util.Map; - -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; - -/** - * - */ -@WebServlet(asyncSupported = true) -public class UpdateRecommendation extends HttpServlet { - private static final long serialVersionUID = 1L; - private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // 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); - - // Check if experiment_name is provided - if (experiment_name == null || experiment_name.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); - } - - // Check if interval_end_time is provided - if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); - } - - // Convert interval_endtime to UTC date format - if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { - sendErrorResponse( - response, - new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), - HttpServletResponse.SC_BAD_REQUEST, - String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) - ); - } - - //Check if data exist - Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); - boolean dataExists = false; - try { - dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); - } catch (Exception e) { - sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - } - - if (dataExists) { - //Load KruizeObject and generate recommendation - Map mainKruizeExperimentMAP = new HashMap<>(); - try { - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { - for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { - for (IntervalResults result : containerData.getResults().values()) { - - } - } - } -// List experimentResultDataList = ; -// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); -// if (!recommendationCheck) -// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", -// experimentResultDataList.get(0).getExperiment_name(), -// experimentResultDataList.get(0).getIntervalEndTime()); -// else { -// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); -// } - } catch (Exception e) { - e.printStackTrace(); - } - } else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); - } - sendSuccessResponse(response, "All ok"); - } - - private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { - response.setContentType(JSON_CONTENT_TYPE); - response.setCharacterEncoding(CHARACTER_ENCODING); - response.setStatus(HttpServletResponse.SC_CREATED); - PrintWriter out = response.getWriter(); - out.append( - new Gson().toJson( - new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") - ) - ); - out.flush(); - } - - public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws - IOException { - if (null != e) { - LOGGER.error(e.toString()); - e.printStackTrace(); - if (null == errorMsg) errorMsg = e.getMessage(); - } - response.sendError(httpStatusCode, errorMsg); - } -} From 52ffa53812458c7b0ba3a552078d5a5eb99c869b Mon Sep 17 00:00:00 2001 From: saakhan Date: Mon, 22 May 2023 16:24:42 +0530 Subject: [PATCH 13/61] add changes for the performance profile table addition in the DB Signed-off-by: saakhan --- .../java/com/autotune/database/helper/DBHelpers.java | 2 +- .../database/service/ExperimentDBService.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/database/helper/DBHelpers.java b/src/main/java/com/autotune/database/helper/DBHelpers.java index c80c223da..49d67722b 100644 --- a/src/main/java/com/autotune/database/helper/DBHelpers.java +++ b/src/main/java/com/autotune/database/helper/DBHelpers.java @@ -54,7 +54,6 @@ public class DBHelpers { private static final Logger LOGGER = LoggerFactory.getLogger(DBHelpers.class); - private DBHelpers() { } @@ -491,6 +490,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 c394ac70c..60b9bfbcf 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -260,6 +260,17 @@ public ValidationOutputData addPerformanceProfileToDB(PerformanceProfile perform return validationOutputData; } + public ValidationOutputData addPerformanceProfileToDB(PerformanceProfile performanceProfile) { + ValidationOutputData validationOutputData = new ValidationOutputData(false, null, null); + try { + KruizePerformanceProfileEntry kruizePerformanceProfileEntry = DBHelpers.Converters.KruizeObjectConverters.convertPerfProfileObjToPerfProfileDBObj(performanceProfile); + validationOutputData = this.experimentDAO.addPerformanceProfileToDB(kruizePerformanceProfileEntry); + } catch (Exception e) { + LOGGER.error("Not able to save Performance Profile due to {}", e.getMessage()); + } + 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, From 1c586579c8d42e2027dd5212c7d189707c653eb2 Mon Sep 17 00:00:00 2001 From: saakhan Date: Thu, 1 Jun 2023 16:51:00 +0530 Subject: [PATCH 14/61] update service methods for performance profiles Signed-off-by: saakhan --- .../autotune/database/dao/ExperimentDAO.java | 4 + .../database/dao/ExperimentDAOImpl.java | 15 + .../autotune/database/helper/DBHelpers.java | 413 ++++++++++++++++++ 3 files changed, 432 insertions(+) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index aa92f3ca1..28629e4c1 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -64,4 +64,8 @@ public interface ExperimentDAO { List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; + // Load a single Performance Profile based on name + List loadPerformanceProfileByName(String performanceProfileName) 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 c618eecad..b0b1d404a 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -479,5 +479,20 @@ public List getKruizeResultsEntry(String experiment_name, Ti return kruizeResultsEntryList; } +<<<<<<< HEAD >>>>>>> d35a6510 (Taking care of duplicate entry to recommendation table) +======= + + 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; + } +>>>>>>> f82f7db7 (update service methods for performance profiles) } diff --git a/src/main/java/com/autotune/database/helper/DBHelpers.java b/src/main/java/com/autotune/database/helper/DBHelpers.java index 49d67722b..a52a3e527 100644 --- a/src/main/java/com/autotune/database/helper/DBHelpers.java +++ b/src/main/java/com/autotune/database/helper/DBHelpers.java @@ -242,6 +242,419 @@ private Converters() { } + public static class KruizeObjectConverters { + private KruizeObjectConverters() { + + } + + /** + * @param apiObject + * @return KruizeExperimentEntry + * This methode facilitate to store data into db by accumulating required data from KruizeObject. + */ + public static KruizeExperimentEntry convertCreateAPIObjToExperimentDBObj(CreateExperimentAPIObject apiObject) { + KruizeExperimentEntry kruizeExperimentEntry = null; + try { + kruizeExperimentEntry = new KruizeExperimentEntry(); + kruizeExperimentEntry.setExperiment_name(apiObject.getExperimentName()); + kruizeExperimentEntry.setExperiment_id(Utils.generateID(apiObject)); + kruizeExperimentEntry.setCluster_name(apiObject.getClusterName()); + kruizeExperimentEntry.setMode(apiObject.getMode()); + kruizeExperimentEntry.setPerformance_profile(apiObject.getPerformanceProfile()); + kruizeExperimentEntry.setVersion(apiObject.getApiVersion()); + kruizeExperimentEntry.setTarget_cluster(apiObject.getTargetCluster()); + kruizeExperimentEntry.setStatus(AnalyzerConstants.ExperimentStatus.IN_PROGRESS); + ObjectMapper objectMapper = new ObjectMapper(); + try { + kruizeExperimentEntry.setExtended_data( + objectMapper.readTree( + new Gson().toJson(apiObject) + ) + ); + } catch (JsonProcessingException e) { + throw new Exception("Error while creating Extended data due to : " + e.getMessage()); + } + } catch (Exception e) { + kruizeExperimentEntry = null; + LOGGER.error("Error while converting Kruize Object to experimentDetailTable due to {}", e.getMessage()); + e.printStackTrace(); + } + return kruizeExperimentEntry; + } + + /** + * @param experimentResultData + * @return KruizeResultsEntry + * This methode facilitate to store data into db by accumulating required data from ExperimentResultData. + */ + public static KruizeResultsEntry convertExperimentResultToExperimentResultsTable(ExperimentResultData experimentResultData) { + KruizeResultsEntry kruizeResultsEntry = null; + Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .enableComplexMapKeySerialization() + .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) + .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) + .create(); + try { + kruizeResultsEntry = new KruizeResultsEntry(); + kruizeResultsEntry.setExperiment_name(experimentResultData.getExperiment_name()); + kruizeResultsEntry.setInterval_start_time(experimentResultData.getIntervalStartTime()); + kruizeResultsEntry.setInterval_end_time(experimentResultData.getIntervalEndTime()); + kruizeResultsEntry.setDuration_minutes( + Double.valueOf((experimentResultData.getIntervalEndTime().getTime() - + experimentResultData.getIntervalStartTime().getTime()) / (60 * 1000)) + ); + Map> k8sObjectsMap = Map.of(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS, experimentResultData.getKubernetes_objects()); + String k8sObjectString = gson.toJson(k8sObjectsMap); + ObjectMapper objectMapper = new ObjectMapper(); + try { + kruizeResultsEntry.setExtended_data( + objectMapper.readTree( + k8sObjectString + ) + ); + } catch (JsonProcessingException e) { + throw new Exception("Error while creating Extended data due to : " + e.getMessage()); + } + } catch (Exception e) { + kruizeResultsEntry = null; + LOGGER.error("Error while converting ExperimentResultData to ExperimentResultsTable due to {}", e.getMessage()); + e.printStackTrace(); + } + return kruizeResultsEntry; + } + + public static ListRecommendationsAPIObject getListRecommendationAPIObjectForDB(KruizeObject kruizeObject, Timestamp monitoringEndTime) { + if (null == kruizeObject) + return null; + if (null == monitoringEndTime) + return null; + if (null == kruizeObject.getKubernetes_objects()) + return null; + if (kruizeObject.getKubernetes_objects().isEmpty()) + return null; + List kubernetesAPIObjectList = new ArrayList<>(); + for (K8sObject k8sObject : kruizeObject.getKubernetes_objects()) { + if (null == k8sObject) + continue; + if (null == k8sObject.getContainerDataMap()) + continue; + if (k8sObject.getContainerDataMap().isEmpty()) + continue; + KubernetesAPIObject kubernetesAPIObject = new KubernetesAPIObject(k8sObject.getName(), k8sObject.getType(), k8sObject.getNamespace()); + boolean matchFound = false; + List containerAPIObjectList = new ArrayList<>(); + for (ContainerData containerData : k8sObject.getContainerDataMap().values()) { + ContainerData clonedContainerData = Utils.getClone(containerData, ContainerData.class); + if (null == clonedContainerData.getContainerRecommendations()) + continue; + if (null == clonedContainerData.getContainerRecommendations().getData()) + continue; + if (clonedContainerData.getContainerRecommendations().getData().isEmpty()) + continue; + HashMap>> recommendations + = clonedContainerData.getContainerRecommendations().getData(); + if (null != monitoringEndTime && recommendations.containsKey(monitoringEndTime)) { + matchFound = true; + ContainerAPIObject containerAPIObject = null; + List tempList = new ArrayList<>(); + for (Timestamp timestamp : recommendations.keySet()) { + if (!timestamp.equals(monitoringEndTime)) + tempList.add(timestamp); + } + for (Timestamp timestamp : tempList) { + recommendations.remove(timestamp); + } + clonedContainerData.getContainerRecommendations().setData(recommendations); + containerAPIObject = new ContainerAPIObject(clonedContainerData.getContainer_name(), + clonedContainerData.getContainer_image_name(), + clonedContainerData.getContainerRecommendations(), + null); + containerAPIObjectList.add(containerAPIObject); + } + } + kubernetesAPIObject.setContainerAPIObjects(containerAPIObjectList); + if (matchFound) { + kubernetesAPIObjectList.add(kubernetesAPIObject); + } + } + ListRecommendationsAPIObject listRecommendationsAPIObject = null; + if (!kubernetesAPIObjectList.isEmpty()) { + listRecommendationsAPIObject = new ListRecommendationsAPIObject(); + listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); + listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); + listRecommendationsAPIObject.setKubernetesObjects(kubernetesAPIObjectList); + } + return listRecommendationsAPIObject; + } + + public static KruizeRecommendationEntry convertKruizeObjectTORecommendation(KruizeObject kruizeObject, ExperimentResultData experimentResultData) { + KruizeRecommendationEntry kruizeRecommendationEntry = null; + Timestamp monitoringEndTime = null; + Boolean checkForTimestamp = false; + Boolean getLatest = true; + Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .enableComplexMapKeySerialization() + .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) + .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) + .create(); + try { + if (null != experimentResultData) { + monitoringEndTime = experimentResultData.getIntervalEndTime(); + } + ListRecommendationsAPIObject listRecommendationsAPIObject = getListRecommendationAPIObjectForDB( + kruizeObject, monitoringEndTime); + if (null == listRecommendationsAPIObject) { + return null; + } + LOGGER.debug(new GsonBuilder().setPrettyPrinting().create().toJson(listRecommendationsAPIObject)); + kruizeRecommendationEntry = new KruizeRecommendationEntry(); + kruizeRecommendationEntry.setExperiment_name(listRecommendationsAPIObject.getExperimentName()); + kruizeRecommendationEntry.setCluster_name(listRecommendationsAPIObject.getClusterName()); + Timestamp endInterval = null; + // todo : what happens if two k8 objects or Containers with different timestamp + for (KubernetesAPIObject k8sObject : listRecommendationsAPIObject.getKubernetesObjects()) { + for (ContainerAPIObject containerAPIObject : k8sObject.getContainerAPIObjects()) { + endInterval = containerAPIObject.getContainerRecommendations().getData().keySet().stream().max(Timestamp::compareTo).get(); + break; + } + } + kruizeRecommendationEntry.setInterval_end_time(endInterval); + Map k8sObjectsMap = Map.of(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS, listRecommendationsAPIObject.getKubernetesObjects()); + String k8sObjectString = gson.toJson(k8sObjectsMap); + ObjectMapper objectMapper = new ObjectMapper(); + DateFormat df = new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT); + objectMapper.setDateFormat(df); + try { + kruizeRecommendationEntry.setExtended_data( + objectMapper.readTree( + k8sObjectString + ) + ); + } catch (JsonProcessingException e) { + throw new Exception("Error while creating Extended data due to : " + e.getMessage()); + } + } catch (Exception e) { + kruizeRecommendationEntry = null; + LOGGER.error("Error while converting KruizeObject to KruizeRecommendationEntry due to {}", e.getMessage()); + e.printStackTrace(); + } + return kruizeRecommendationEntry; + } + + public static List convertExperimentEntryToCreateExperimentAPIObject(List entries) throws Exception { + List createExperimentAPIObjects = new ArrayList<>(); + int failureThreshHold = entries.size(); + int failureCount = 0; + for (KruizeExperimentEntry entry : entries) { + try { + JsonNode extended_data = entry.getExtended_data(); + String extended_data_rawJson = extended_data.toString(); + CreateExperimentAPIObject apiObj = new Gson().fromJson(extended_data_rawJson, CreateExperimentAPIObject.class); + apiObj.setExperiment_id(entry.getExperiment_id()); + apiObj.setStatus(entry.getStatus()); + createExperimentAPIObjects.add(apiObj); + } catch (Exception e) { + LOGGER.error("Error in converting to apiObj from db object due to : {}", e.getMessage()); + LOGGER.error(entry.toString()); + failureCount++; + } + } + if (failureThreshHold > 0 && failureCount == failureThreshHold) + throw new Exception("None of the experiments are able to load from DB."); + + return createExperimentAPIObjects; + } + + public static List convertResultEntryToUpdateResultsAPIObject(List kruizeResultsEntries) { + ObjectMapper mapper = new ObjectMapper(); + DateFormat df = new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT); + mapper.setDateFormat(df); + Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .enableComplexMapKeySerialization() + .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) + .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) + .create(); + List updateResultsAPIObjects = new ArrayList<>(); + for (KruizeResultsEntry kruizeResultsEntry : kruizeResultsEntries) { + try { + UpdateResultsAPIObject updateResultsAPIObject = new UpdateResultsAPIObject(); + updateResultsAPIObject.setExperimentName(kruizeResultsEntry.getExperiment_name()); + updateResultsAPIObject.setStartTimestamp(kruizeResultsEntry.getInterval_start_time()); + updateResultsAPIObject.setEndTimestamp(kruizeResultsEntry.getInterval_end_time()); + JsonNode extendedDataNode = kruizeResultsEntry.getExtended_data(); + JsonNode k8sObjectsNode = extendedDataNode.get(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS); + List k8sObjectList = new ArrayList<>(); + if (k8sObjectsNode.isArray()) { + for (JsonNode node : k8sObjectsNode) { + K8sObject k8sObject = gson.fromJson(mapper.writeValueAsString(node), K8sObject.class); + if (null != k8sObject) { + k8sObjectList.add(k8sObject); + } else { + LOGGER.debug("GSON failed to convert the DB Json object in convertResultEntryToUpdateResultsAPIObject"); + } + } + } + List kubernetesAPIObjectList = convertK8sObjectListToKubernetesAPIObjectList(k8sObjectList); + updateResultsAPIObject.setKubernetesObjects(kubernetesAPIObjectList); + updateResultsAPIObjects.add(updateResultsAPIObject); + } catch (Exception e) { + LOGGER.error("Exception occurred while updating local storage: {}", e.getMessage()); + e.printStackTrace(); + } + } + return updateResultsAPIObjects; + } + + private static List convertK8sObjectListToKubernetesAPIObjectList(List k8sObjectList) throws JsonProcessingException { + List kubernetesAPIObjects = new ArrayList<>(); + for (K8sObject k8sObject : k8sObjectList) { + KubernetesAPIObject kubernetesAPIObject = new KubernetesAPIObject( + k8sObject.getName(), + k8sObject.getType(), + k8sObject.getNamespace() + ); + List containerAPIObjects = new ArrayList<>(); + for (Map.Entry entry : k8sObject.getContainerDataMap().entrySet()) { + containerAPIObjects.add(new ContainerAPIObject( + entry.getKey(), + entry.getValue().getContainer_image_name(), + entry.getValue().getContainerRecommendations(), + new ArrayList<>(entry.getValue().getMetrics().values()) + )); + } + kubernetesAPIObject.setContainerAPIObjects(containerAPIObjects); + kubernetesAPIObjects.add(kubernetesAPIObject); + } + return kubernetesAPIObjects; + } + + public static List convertRecommendationEntryToRecommendationAPIObject( + List kruizeRecommendationEntryList) throws InvalidConversionOfRecommendationEntryException { + if (null == kruizeRecommendationEntryList) + return null; + if (kruizeRecommendationEntryList.size() == 0) + return null; + Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .enableComplexMapKeySerialization() + .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) + .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) + .create(); + List listRecommendationsAPIObjectList = new ArrayList<>(); + for (KruizeRecommendationEntry kruizeRecommendationEntry : kruizeRecommendationEntryList) { + // Check if instance of KruizeRecommendationEntry is null + if (null == kruizeRecommendationEntry) { + // Throw an exception stating it cannot be null + throw new InvalidConversionOfRecommendationEntryException( + String.format( + AnalyzerErrorConstants.ConversionErrors.KruizeRecommendationError.NOT_NULL, + KruizeRecommendationEntry.class.getSimpleName() + ) + ); + } + // Create an Object Mapper to extract value from JSON Node + ObjectMapper objectMapper = new ObjectMapper(); + DateFormat df = new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT); + objectMapper.setDateFormat(df); + // Create a holder for recommendation object to save the result from object mapper + ListRecommendationsAPIObject listRecommendationsAPIObject = null; + JsonNode extendedData = kruizeRecommendationEntry.getExtended_data().get(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS); + if (null == extendedData) + continue; + try { + // If successful, the object mapper returns the list recommendation API Object + List kubernetesAPIObjectList = new ArrayList<>(); + if (extendedData.isArray()) { + for (JsonNode node : extendedData) { + KubernetesAPIObject kubernetesAPIObject = gson.fromJson(objectMapper.writeValueAsString(node), KubernetesAPIObject.class); + if (null != kubernetesAPIObject) { + kubernetesAPIObjectList.add(kubernetesAPIObject); + } else { + LOGGER.debug("GSON failed to convert the DB Json object in convertRecommendationEntryToRecommendationAPIObject"); + } + } + } + if (null != kubernetesAPIObjectList) { + listRecommendationsAPIObject = new ListRecommendationsAPIObject(); + listRecommendationsAPIObject.setKubernetesObjects(kubernetesAPIObjectList); + listRecommendationsAPIObject.setExperimentName(kruizeRecommendationEntry.getExperiment_name()); + listRecommendationsAPIObject.setClusterName(kruizeRecommendationEntry.getCluster_name()); + } + } catch (JsonProcessingException e) { + e.printStackTrace(); + LOGGER.debug(e.getMessage()); + } + if (null != listRecommendationsAPIObject) + listRecommendationsAPIObjectList.add(listRecommendationsAPIObject); + } + if (listRecommendationsAPIObjectList.isEmpty()) + return null; + return listRecommendationsAPIObjectList; + } + + public static KruizePerformanceProfileEntry convertPerfProfileObjToPerfProfileDBObj(PerformanceProfile performanceProfile) { + KruizePerformanceProfileEntry kruizePerformanceProfileEntry = null; + try { + kruizePerformanceProfileEntry = new KruizePerformanceProfileEntry(); + kruizePerformanceProfileEntry.setName(performanceProfile.getName()); + kruizePerformanceProfileEntry.setProfile_version(performanceProfile.getProfile_version()); + kruizePerformanceProfileEntry.setK8s_type(performanceProfile.getK8S_TYPE()); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + kruizePerformanceProfileEntry.setSlo( + objectMapper.readTree(new Gson().toJson(performanceProfile.getSloInfo()))); + } catch (JsonProcessingException e) { + throw new Exception("Error while creating SLO data due to : " + e.getMessage()); + } + } catch (Exception e) { + LOGGER.error("Error occurred while converting Performance Profile Object to PerformanceProfile table due to {}", e.getMessage()); + e.printStackTrace(); + } + return kruizePerformanceProfileEntry; + } + + public static List convertPerformanceProfileEntryToPerformanceProfileObject(List entries) throws Exception { + List performanceProfiles = new ArrayList<>(); + int failureThreshHold = entries.size(); + int failureCount = 0; + for (KruizePerformanceProfileEntry entry : entries) { + try { + JsonNode sloData = entry.getSlo(); + String slo_rawJson = sloData.toString(); + PerformanceProfile performanceProfile = new Gson().fromJson(slo_rawJson, PerformanceProfile.class); + performanceProfile.setName(entry.getName()); + performanceProfile.setProfile_version(entry.getProfile_version()); + performanceProfile.setK8s_type(entry.getK8s_type()); + performanceProfiles.add(performanceProfile); + } catch (Exception e) { + LOGGER.error("Error occurred while reading from Performance Profile DB object due to : {}", e.getMessage()); + LOGGER.error(entry.toString()); + failureCount++; + } + } + if (failureThreshHold > 0 && failureCount == failureThreshHold) + throw new Exception("None of the Performance Profiles loaded from DB."); + + return performanceProfiles; + } + + } + } + + public static class Converters { + private Converters() { + + } + + public static class KruizeObjectConverters { private KruizeObjectConverters() { From 40a70998570c8b207c969488249d742ef7679355 Mon Sep 17 00:00:00 2001 From: saakhan Date: Tue, 6 Jun 2023 16:31:29 +0530 Subject: [PATCH 15/61] fix issue with the sloData not getting populated and other minor changes Signed-off-by: saakhan --- src/main/java/com/autotune/database/helper/DBHelpers.java | 7 +++---- .../com/autotune/database/service/ExperimentDBService.java | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/autotune/database/helper/DBHelpers.java b/src/main/java/com/autotune/database/helper/DBHelpers.java index a52a3e527..578a0824e 100644 --- a/src/main/java/com/autotune/database/helper/DBHelpers.java +++ b/src/main/java/com/autotune/database/helper/DBHelpers.java @@ -629,10 +629,9 @@ public static List convertPerformanceProfileEntryToPerforman try { JsonNode sloData = entry.getSlo(); String slo_rawJson = sloData.toString(); - PerformanceProfile performanceProfile = new Gson().fromJson(slo_rawJson, PerformanceProfile.class); - performanceProfile.setName(entry.getName()); - performanceProfile.setProfile_version(entry.getProfile_version()); - performanceProfile.setK8s_type(entry.getK8s_type()); + SloInfo sloInfo = new Gson().fromJson(slo_rawJson, SloInfo.class); + PerformanceProfile performanceProfile = new PerformanceProfile( + entry.getName(), entry.getProfile_version(), entry.getK8s_type(), sloInfo); performanceProfiles.add(performanceProfile); } catch (Exception e) { LOGGER.error("Error occurred while reading from Performance Profile DB object due to : {}", e.getMessage()); diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 60b9bfbcf..87d79d39f 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -144,6 +144,7 @@ public void loadAllPerformanceProfiles(Map performan } 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 List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, interval_end_time, limitRows); From e55c51abd1be6f5e1e81255779f98117fd3f171e Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 16/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 147 ++++++++++++++++++ .../autotune/database/dao/ExperimentDAO.java | 1 - 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java new file mode 100644 index 000000000..b5dbed42f --- /dev/null +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2022 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.services; + +import com.autotune.analyzer.exceptions.KruizeResponse; +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.common.data.result.ContainerData; +import com.autotune.common.data.result.IntervalResults; +import com.autotune.common.k8sObjects.K8sObject; +import com.autotune.database.service.ExperimentDBService; +import com.autotune.utils.KruizeConstants; +import com.autotune.utils.Utils; +import com.google.gson.Gson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.Map; + +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; + +/** + * + */ +@WebServlet(asyncSupported = true) +public class UpdateRecommendation extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // 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); + + // Check if experiment_name is provided + if (experiment_name == null || experiment_name.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); + } + + // Check if interval_end_time is provided + if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); + } + + // Convert interval_endtime to UTC date format + if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { + sendErrorResponse( + response, + new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), + HttpServletResponse.SC_BAD_REQUEST, + String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) + ); + } + + //Check if data exist + Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); + boolean dataExists = false; + try { + dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + } catch (Exception e) { + sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + + if (dataExists) { + //Load KruizeObject and generate recommendation + Map mainKruizeExperimentMAP = new HashMap<>(); + try { + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); + KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { + for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { + for (IntervalResults result : containerData.getResults().values()) { + + } + } + } +// List experimentResultDataList = ; +// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); +// if (!recommendationCheck) +// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", +// experimentResultDataList.get(0).getExperiment_name(), +// experimentResultDataList.get(0).getIntervalEndTime()); +// else { +// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); +// } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); + } + sendSuccessResponse(response, "All ok"); + } + + private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { + response.setContentType(JSON_CONTENT_TYPE); + response.setCharacterEncoding(CHARACTER_ENCODING); + response.setStatus(HttpServletResponse.SC_CREATED); + PrintWriter out = response.getWriter(); + out.append( + new Gson().toJson( + new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") + ) + ); + out.flush(); + } + + public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws + IOException { + if (null != e) { + LOGGER.error(e.toString()); + e.printStackTrace(); + if (null == errorMsg) errorMsg = e.getMessage(); + } + response.sendError(httpStatusCode, errorMsg); + } +} diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 28629e4c1..411ef75a0 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -63,7 +63,6 @@ public interface ExperimentDAO { // Get KruizeResult Record List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; - // Load a single Performance Profile based on name List loadPerformanceProfileByName(String performanceProfileName) throws Exception; From 42477dd7b597e3ef597af2c75caea1891f346ef2 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 20 May 2023 21:41:51 +0530 Subject: [PATCH 17/61] UpdateRecommendation API E2E working code is ready. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 49 +++++++++---------- .../autotune/database/dao/ExperimentDAO.java | 2 + 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index b5dbed42f..ea05c2493 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -16,11 +16,10 @@ package com.autotune.analyzer.services; import com.autotune.analyzer.exceptions.KruizeResponse; +import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ContainerData; -import com.autotune.common.data.result.IntervalResults; -import com.autotune.common.k8sObjects.K8sObject; +import com.autotune.common.data.result.ExperimentResultData; import com.autotune.database.service.ExperimentDBService; import com.autotune.utils.KruizeConstants; import com.autotune.utils.Utils; @@ -37,6 +36,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.sql.Timestamp; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -65,13 +65,16 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) // Check if experiment_name is provided if (experiment_name == null || experiment_name.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); + return; } // Check if interval_end_time is provided if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); + return; } + LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr); // Convert interval_endtime to UTC date format if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { sendErrorResponse( @@ -80,46 +83,43 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) HttpServletResponse.SC_BAD_REQUEST, String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) ); + return; } //Check if data exist Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); - boolean dataExists = false; + ExperimentResultData experimentResultData = null; try { - dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); } catch (Exception e) { sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + return; } - if (dataExists) { + if (null != experimentResultData) { //Load KruizeObject and generate recommendation Map mainKruizeExperimentMAP = new HashMap<>(); try { - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { - for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { - for (IntervalResults result : containerData.getResults().values()) { - - } - } + // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time + long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); + Timestamp interval_start_time = new Timestamp(subtractedTime); + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); + boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + if (!recommendationCheck) + LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", + experimentResultData.getExperiment_name(), + experimentResultData.getIntervalEndTime()); + else { + new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); } -// List experimentResultDataList = ; -// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); -// if (!recommendationCheck) -// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", -// experimentResultDataList.get(0).getExperiment_name(), -// experimentResultDataList.get(0).getIntervalEndTime()); -// else { -// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); -// } } catch (Exception e) { e.printStackTrace(); } } else { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); + return; } - sendSuccessResponse(response, "All ok"); } private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { @@ -139,7 +139,6 @@ public void sendErrorResponse(HttpServletResponse response, Exception e, int htt IOException { if (null != e) { LOGGER.error(e.toString()); - e.printStackTrace(); if (null == errorMsg) errorMsg = e.getMessage(); } response.sendError(httpStatusCode, errorMsg); diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 411ef75a0..88b053113 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -66,5 +66,7 @@ public interface ExperimentDAO { // Load a single Performance Profile based on name List loadPerformanceProfileByName(String performanceProfileName) throws Exception; + // Get KruizeResult Record + KruizeResultsEntry getKruizeResultsEntry(String experiment_name, Timestamp interval_end_time) throws Exception; } From a897c68291eab82db24deb1028abf7fb2058e072 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 26 May 2023 20:32:47 +0530 Subject: [PATCH 18/61] Added exception conditions. Signed-off-by: msvinaykumar --- .../analyzer/services/UpdateRecommendation.java | 9 +++++++-- .../database/service/ExperimentDBService.java | 11 ----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index ea05c2493..a25a20ab1 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -18,6 +18,7 @@ import com.autotune.analyzer.exceptions.KruizeResponse; import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ExperimentResultData; import com.autotune.database.service.ExperimentDBService; @@ -110,8 +111,12 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) experimentResultData.getExperiment_name(), experimentResultData.getIntervalEndTime()); else { - new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); + boolean success = new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + if (success) + sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); + else { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerConstants.RecommendationNotificationMsgConstant.NOT_ENOUGH_DATA); + } } } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 87d79d39f..6420db99e 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -261,17 +261,6 @@ public ValidationOutputData addPerformanceProfileToDB(PerformanceProfile perform return validationOutputData; } - public ValidationOutputData addPerformanceProfileToDB(PerformanceProfile performanceProfile) { - ValidationOutputData validationOutputData = new ValidationOutputData(false, null, null); - try { - KruizePerformanceProfileEntry kruizePerformanceProfileEntry = DBHelpers.Converters.KruizeObjectConverters.convertPerfProfileObjToPerfProfileDBObj(performanceProfile); - validationOutputData = this.experimentDAO.addPerformanceProfileToDB(kruizePerformanceProfileEntry); - } catch (Exception e) { - LOGGER.error("Not able to save Performance Profile due to {}", e.getMessage()); - } - 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, From eb1e94158fdede429cc7b865a44d3ee923fdd50f Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 14:49:48 +0530 Subject: [PATCH 19/61] Taking care of duplicate entry to recommendation table Signed-off-by: msvinaykumar --- .../autotune/database/dao/ExperimentDAO.java | 5 -- .../database/dao/ExperimentDAOImpl.java | 49 ------------------- .../database/service/ExperimentDBService.java | 4 +- 3 files changed, 1 insertion(+), 57 deletions(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 88b053113..aa92f3ca1 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -63,10 +63,5 @@ public interface ExperimentDAO { // Get KruizeResult Record List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; - // Load a single Performance Profile based on name - List loadPerformanceProfileByName(String performanceProfileName) throws Exception; - - // Get KruizeResult Record - KruizeResultsEntry getKruizeResultsEntry(String experiment_name, 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 b0b1d404a..51dc6e84c 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -398,39 +398,6 @@ public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(Stri return recommendationEntries; } -<<<<<<< HEAD - @Override - public List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { - List kruizeResultsEntryList = new ArrayList<>(); - try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { - - if (interval_start_time != null && interval_end_time != null) { - kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_START_END_TIME, KruizeResultsEntry.class) - .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name) - .setParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME, interval_start_time) - .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) - .getResultList(); - } else if (interval_end_time != null) { - kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME, KruizeResultsEntry.class) - .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name) - .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) - .getResultList(); - } else { - kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_MAX_END_TIME, KruizeResultsEntry.class) - .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; - } catch (Exception e) { - kruizeResultsEntryList = null; - LOGGER.error("Not able to load results due to: {}", e.getMessage()); - throw new Exception("Error while loading results from the database due to : " + e.getMessage()); - } - return kruizeResultsEntryList; - } -======= public List loadPerformanceProfileByName(String performanceProfileName) throws Exception { List entries = null; @@ -479,20 +446,4 @@ public List getKruizeResultsEntry(String experiment_name, Ti return kruizeResultsEntryList; } -<<<<<<< HEAD ->>>>>>> d35a6510 (Taking care of duplicate entry to recommendation table) -======= - - 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; - } ->>>>>>> f82f7db7 (update service methods for performance profiles) } diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 6420db99e..b76d481ab 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -54,6 +54,7 @@ public ExperimentDBService() { this.experimentDAO = new ExperimentDAOImpl(); } + public void loadAllExperiments(Map mainKruizeExperimentMap) throws Exception { ExperimentInterface experimentInterface = new ExperimentInterfaceImpl(); List entries = experimentDAO.loadAllExperiments(); @@ -144,7 +145,6 @@ public void loadAllPerformanceProfiles(Map performan } 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 List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, interval_end_time, limitRows); @@ -215,7 +215,6 @@ public List addResultsToDB(List re return failedUpdateResultsAPIObjects; } - public ValidationOutputData addRecommendationToDB(Map experimentsMap, List experimentResultDataList) { ValidationOutputData validationOutputData = new ValidationOutputData(false, "", null); if (null == experimentResultDataList) { @@ -345,7 +344,6 @@ 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); From e59e21d6c6249b2945a79ed9dded1229ff9b0bb0 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 19 Jun 2023 15:58:41 +0530 Subject: [PATCH 20/61] Date range update recommendations are handled Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/utils/AnalyzerErrorConstants.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java index 7c145bade..915872a46 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -135,6 +135,9 @@ public static final class UpdateRecommendationsAPI { 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); + public static final String TIME_COMPARE = "The Start time should precede the End time!"; + + private UpdateRecommendationsAPI() { } } From 8018c258e24c31095a58c60cab46a47ba86fe6f7 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 14 Jul 2023 18:32:56 +0530 Subject: [PATCH 21/61] Bulk upload results Signed-off-by: msvinaykumar --- pom.xml | 7 + .../exceptions/KruizeErrorHandler.java | 7 +- .../analyzer/exceptions/KruizeResponse.java | 15 ++ .../experiment/ExperimentInitiator.java | 113 +++++++--- .../ExperimentResultValidation.java | 194 +----------------- .../analyzer/serviceObjects/BaseSO.java | 13 ++ .../UpdateResultsAPIObject.java | 42 +++- .../verification/annotators/CompareDate.java | 36 ++++ .../annotators/ExperimentNameExist.java | 38 ++++ .../annotators/KubernetesElementsCheck.java | 37 ++++ .../annotators/PerformanceProfileCheck.java | 35 ++++ .../annotators/TimeDifferenceCheck.java | 36 ++++ .../validators/CompareDateValidator.java | 50 +++++ .../ExperimentNameExistValidator.java | 59 ++++++ .../KubernetesElementsValidator.java | 100 +++++++++ .../PerformanceProfileValidator.java | 67 ++++++ .../validators/TimeDifferenceValidator.java | 54 +++++ .../analyzer/services/UpdateResults.java | 3 - .../utils/AnalyzerErrorConstants.java | 3 - .../data/metrics/MetricPercentileResults.java | 18 +- .../com/autotune/utils/KruizeConstants.java | 2 +- 21 files changed, 685 insertions(+), 244 deletions(-) create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/CompareDate.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/ExperimentNameExist.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/KubernetesElementsCheck.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/PerformanceProfileCheck.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/TimeDifferenceCheck.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/KubernetesElementsValidator.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java create mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/TimeDifferenceValidator.java 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/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..c114a9819 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())) { @@ -112,5 +93,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/serviceObjects/BaseSO.java b/src/main/java/com/autotune/analyzer/serviceObjects/BaseSO.java index fa5bacf06..bdea150e6 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/BaseSO.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/BaseSO.java @@ -15,11 +15,17 @@ *******************************************************************************/ package com.autotune.analyzer.serviceObjects; +import com.autotune.analyzer.serviceObjects.verification.annotators.ExperimentNameExist; import com.google.gson.annotations.SerializedName; +import org.hibernate.validator.constraints.NotBlank; + public abstract class BaseSO { + @NotBlank(groups = InitialValidation.class) @SerializedName("version") private String apiVersion; + @NotBlank(groups = InitialValidation.class) + @ExperimentNameExist(groups = ExperimentNameExistValidation.class) @SerializedName("experiment_name") private String experimentName; @@ -38,4 +44,11 @@ public String getExperimentName() { public void setExperimentName(String experimentName) { this.experimentName = experimentName; } + + public interface InitialValidation { + } + + public interface ExperimentNameExistValidation { + } + } diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java b/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java index ad3c5b2c5..033457e76 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java @@ -15,20 +15,43 @@ *******************************************************************************/ package com.autotune.analyzer.serviceObjects; +import com.autotune.analyzer.serviceObjects.verification.annotators.CompareDate; +import com.autotune.analyzer.serviceObjects.verification.annotators.KubernetesElementsCheck; +import com.autotune.analyzer.serviceObjects.verification.annotators.PerformanceProfileCheck; +import com.autotune.analyzer.serviceObjects.verification.annotators.TimeDifferenceCheck; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.utils.KruizeConstants; import com.google.gson.annotations.SerializedName; +import jakarta.validation.GroupSequence; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.sql.Timestamp; import java.util.List; -public class UpdateResultsAPIObject extends BaseSO{ + +@CompareDate(groups = BaseSO.InitialValidation.class, message = AnalyzerErrorConstants.AutotuneObjectErrors.WRONG_TIMESTAMP) +@TimeDifferenceCheck(groups = UpdateResultsAPIObject.EvaluateRemainingConstraints.class, message = AnalyzerErrorConstants.AutotuneObjectErrors.MEASUREMENT_DURATION_ERROR) +@PerformanceProfileCheck(groups = UpdateResultsAPIObject.EvaluateRemainingConstraints.class) +@KubernetesElementsCheck(groups = UpdateResultsAPIObject.EvaluateRemainingConstraints.class) +public class UpdateResultsAPIObject extends BaseSO { + + @NotNull(groups = InitialValidation.class) @SerializedName(KruizeConstants.JSONKeys.INTERVAL_START_TIME) public Timestamp startTimestamp; + + + @NotNull(groups = InitialValidation.class) @SerializedName(KruizeConstants.JSONKeys.INTERVAL_END_TIME) public Timestamp endTimestamp; + + @NotNull(groups = InitialValidation.class) + @Size(min = 1, max = 1, message = AnalyzerErrorConstants.AutotuneObjectErrors.UNSUPPORTED_BULK_KUBERNETES) @SerializedName(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS) private 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[] 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[] 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[] 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[] 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[] 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..781aff81a --- /dev/null +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * 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; + int comparisonResult = updateResultsAPIObject.getStartTimestamp().compareTo(updateResultsAPIObject.getEndTimestamp()); + if (comparisonResult < 0) { + success = true; + } + /* if (comparisonResult >= 0) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate("") + .addPropertyNode("") + .addConstraintViolation(); + } else { + 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..f95df7da5 --- /dev/null +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * 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 = ""; + // 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..95429e61e --- /dev/null +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/KubernetesElementsValidator.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * 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; + 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; + } + + 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..c7a73a596 --- /dev/null +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * 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; + +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()); + 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..1602ae2ac --- /dev/null +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/TimeDifferenceValidator.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * 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()); + + Double parsedMeasurementDuration = kruizeObject.getTrial_settings().getMeasurement_durationMinutes_inDouble(); + IntervalResults intervalResults = new IntervalResults(updateResultsAPIObject.getStartTimestamp(), updateResultsAPIObject.getEndTimestamp()); + Double durationInSeconds = intervalResults.getDuration_in_seconds(); + // 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/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 6c1a16568..44aacd8e1 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -20,11 +20,8 @@ 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.operator.KruizeDeploymentInfo; import com.autotune.utils.MetricsConfig; diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java index 915872a46..7c145bade 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -135,9 +135,6 @@ public static final class UpdateRecommendationsAPI { 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); - public static final String TIME_COMPARE = "The Start time should precede the End time!"; - - 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/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java index cdb744629..6bba9230c 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() { } From 38f0c71814e8a37c9d4004c1e31587a28b0573de Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 17 Jul 2023 10:26:31 +0530 Subject: [PATCH 22/61] resolved conflicts Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/serviceObjects/Converters.java | 2 +- .../com/autotune/database/table/KruizeResultsEntry.java | 8 ++++++++ src/main/java/com/autotune/utils/KruizeConstants.java | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java index db4673dcc..e3ca02805 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java @@ -97,7 +97,7 @@ public static ListRecommendationsAPIObject convertKruizeObjectToListRecommendati Timestamp monitoringEndTime) { ListRecommendationsAPIObject listRecommendationsAPIObject = new ListRecommendationsAPIObject(); try { - listRecommendationsAPIObject.setApiVersion(kruizeObject.getApiVersion()); + listRecommendationsAPIObject.setApiVersion(kruizeObject.getApiVersion()); // todo what if listRecommendations list two recommendation with different version listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); List kubernetesAPIObjects = new ArrayList<>(); diff --git a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java index 0f443df35..3e284ccf8 100644 --- a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java +++ b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java @@ -102,4 +102,12 @@ public String getVersion() { public void setVersion(String version) { this.version = version; } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } } diff --git a/src/main/java/com/autotune/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java index 6bba9230c..19a746e37 100644 --- a/src/main/java/com/autotune/utils/KruizeConstants.java +++ b/src/main/java/com/autotune/utils/KruizeConstants.java @@ -56,6 +56,11 @@ private StartUpMode() { } } + public static final class Versions { + public static final String KRUIZE_RESULTS_API_VERSION = "1.0"; + public static final String KRUIZE_RECOMMENDATION_API_VERSION = "1.0"; + } + public static final class HpoOperations { public static final String EXP_TRIAL_GENERATE_NEW = "EXP_TRIAL_GENERATE_NEW"; public static final String EXP_TRIAL_GENERATE_SUBSEQUENT = "EXP_TRIAL_GENERATE_SUBSEQUENT"; From f1f7131c64dbbd47f4f8ed2115c801ef8e8bead0 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 6 Jul 2023 17:38:10 +0530 Subject: [PATCH 23/61] incorporated review comments Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/serviceObjects/Converters.java | 2 +- src/main/java/com/autotune/utils/KruizeConstants.java | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java index e3ca02805..db4673dcc 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java @@ -97,7 +97,7 @@ public static ListRecommendationsAPIObject convertKruizeObjectToListRecommendati Timestamp monitoringEndTime) { ListRecommendationsAPIObject listRecommendationsAPIObject = new ListRecommendationsAPIObject(); try { - listRecommendationsAPIObject.setApiVersion(kruizeObject.getApiVersion()); // todo what if listRecommendations list two recommendation with different version + listRecommendationsAPIObject.setApiVersion(kruizeObject.getApiVersion()); listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); List kubernetesAPIObjects = new ArrayList<>(); diff --git a/src/main/java/com/autotune/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java index 19a746e37..6bba9230c 100644 --- a/src/main/java/com/autotune/utils/KruizeConstants.java +++ b/src/main/java/com/autotune/utils/KruizeConstants.java @@ -56,11 +56,6 @@ private StartUpMode() { } } - public static final class Versions { - public static final String KRUIZE_RESULTS_API_VERSION = "1.0"; - public static final String KRUIZE_RECOMMENDATION_API_VERSION = "1.0"; - } - public static final class HpoOperations { public static final String EXP_TRIAL_GENERATE_NEW = "EXP_TRIAL_GENERATE_NEW"; public static final String EXP_TRIAL_GENERATE_SUBSEQUENT = "EXP_TRIAL_GENERATE_SUBSEQUENT"; From 4cbf5f690528073607414e240951e72903202035 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 17 Jul 2023 13:08:50 +0530 Subject: [PATCH 24/61] resolved conflicts Signed-off-by: msvinaykumar --- .../autotune/database/table/KruizeResultsEntry.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java index 3e284ccf8..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; } @@ -103,11 +107,11 @@ public void setVersion(String version) { this.version = version; } - public String getVersion() { - return version; + public List getErrorReasons() { + return errorReasons; } - public void setVersion(String version) { - this.version = version; + public void setErrorReasons(List errorReasons) { + this.errorReasons = errorReasons; } } From ad541f00e3721b493fecf4e367ec10e05ad93260 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 25 Jul 2023 12:46:44 +0530 Subject: [PATCH 25/61] incorporated review comments Signed-off-by: msvinaykumar --- .../validators/CompareDateValidator.java | 16 +++++----------- .../analyzer/services/UpdateResults.java | 1 + .../autotune/operator/InitializeDeployment.java | 7 +++++-- .../autotune/operator/KruizeDeploymentInfo.java | 1 + .../java/com/autotune/utils/KruizeConstants.java | 3 +++ 5 files changed, 15 insertions(+), 13 deletions(-) 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 index 781aff81a..caef8701e 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java @@ -33,18 +33,12 @@ public void initialize(CompareDate constraintAnnotation) { @Override public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) { boolean success = false; - int comparisonResult = updateResultsAPIObject.getStartTimestamp().compareTo(updateResultsAPIObject.getEndTimestamp()); - if (comparisonResult < 0) { - success = true; + if (null != updateResultsAPIObject.getStartTimestamp() && null != updateResultsAPIObject.getEndTimestamp()) { + int comparisonResult = updateResultsAPIObject.getStartTimestamp().compareTo(updateResultsAPIObject.getEndTimestamp()); + if (comparisonResult < 0) { + success = true; + } } - /* if (comparisonResult >= 0) { - context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate("") - .addPropertyNode("") - .addConstraintViolation(); - } else { - success = true; - }*/ return success; } } diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 44aacd8e1..a150bae51 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -22,6 +22,7 @@ import com.autotune.analyzer.performanceProfiles.PerformanceProfile; import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject; import com.autotune.analyzer.utils.AnalyzerConstants; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ExperimentResultData; import com.autotune.operator.KruizeDeploymentInfo; import com.autotune.utils.MetricsConfig; 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/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java index 6bba9230c..dbd6c7920 100644 --- a/src/main/java/com/autotune/utils/KruizeConstants.java +++ b/src/main/java/com/autotune/utils/KruizeConstants.java @@ -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"; From a7de1f17e6ad8a94a3e71be8f8fef5d614acd863 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 26/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 63 +++++++++++++++++++ src/main/java/com/autotune/utils/Utils.java | 1 - 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index a25a20ab1..c10e2fda7 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -16,11 +16,19 @@ package com.autotune.analyzer.services; import com.autotune.analyzer.exceptions.KruizeResponse; +<<<<<<< HEAD import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ExperimentResultData; +======= +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.common.data.result.ContainerData; +import com.autotune.common.data.result.IntervalResults; +import com.autotune.common.k8sObjects.K8sObject; +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) import com.autotune.database.service.ExperimentDBService; import com.autotune.utils.KruizeConstants; import com.autotune.utils.Utils; @@ -37,7 +45,10 @@ import java.io.IOException; import java.io.PrintWriter; import java.sql.Timestamp; +<<<<<<< HEAD import java.util.Collections; +======= +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) import java.util.HashMap; import java.util.Map; @@ -66,16 +77,24 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) // Check if experiment_name is provided if (experiment_name == null || experiment_name.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); +<<<<<<< HEAD return; +======= +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) } // Check if interval_end_time is provided if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); +<<<<<<< HEAD return; } LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr); +======= + } + +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) // Convert interval_endtime to UTC date format if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { sendErrorResponse( @@ -84,11 +103,15 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) HttpServletResponse.SC_BAD_REQUEST, String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) ); +<<<<<<< HEAD return; +======= +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) } //Check if data exist Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); +<<<<<<< HEAD ExperimentResultData experimentResultData = null; try { experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); @@ -118,13 +141,49 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerConstants.RecommendationNotificationMsgConstant.NOT_ENOUGH_DATA); } } +======= + boolean dataExists = false; + try { + dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + } catch (Exception e) { + sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + + if (dataExists) { + //Load KruizeObject and generate recommendation + Map mainKruizeExperimentMAP = new HashMap<>(); + try { + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); + KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { + for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { + for (IntervalResults result : containerData.getResults().values()) { + + } + } + } +// List experimentResultDataList = ; +// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); +// if (!recommendationCheck) +// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", +// experimentResultDataList.get(0).getExperiment_name(), +// experimentResultDataList.get(0).getIntervalEndTime()); +// else { +// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); +// } +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) } catch (Exception e) { e.printStackTrace(); } } else { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); +<<<<<<< HEAD return; } +======= + } + sendSuccessResponse(response, "All ok"); +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) } private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { @@ -144,6 +203,10 @@ public void sendErrorResponse(HttpServletResponse response, Exception e, int htt IOException { if (null != e) { LOGGER.error(e.toString()); +<<<<<<< HEAD +======= + e.printStackTrace(); +>>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) if (null == errorMsg) errorMsg = e.getMessage(); } response.sendError(httpStatusCode, errorMsg); diff --git a/src/main/java/com/autotune/utils/Utils.java b/src/main/java/com/autotune/utils/Utils.java index 2d5e232f7..2a0321b08 100644 --- a/src/main/java/com/autotune/utils/Utils.java +++ b/src/main/java/com/autotune/utils/Utils.java @@ -235,7 +235,6 @@ public static Timestamp getTimeStampFrom(String format, String date) { // Convert the timestamp to UTC Instant desiredInstant = localDateTime.toInstant(ZoneOffset.UTC); Timestamp convertedDate = Timestamp.from(desiredInstant); - return convertedDate; } catch (Exception e) { From 4e7ad666951875c9c284d81228c0d40efde20b3f Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 20 May 2023 21:41:51 +0530 Subject: [PATCH 27/61] UpdateRecommendation API E2E working code is ready. Signed-off-by: msvinaykumar --- .../java/com/autotune/analyzer/Analyzer.java | 1 + .../services/UpdateRecommendation.java | 65 ++++++++++++++++--- .../autotune/database/dao/ExperimentDAO.java | 1 - src/main/java/com/autotune/utils/Utils.java | 1 + 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/Analyzer.java b/src/main/java/com/autotune/analyzer/Analyzer.java index b8c9ee2c5..52fd1d536 100644 --- a/src/main/java/com/autotune/analyzer/Analyzer.java +++ b/src/main/java/com/autotune/analyzer/Analyzer.java @@ -48,6 +48,7 @@ public static void addServlets(ServletContextHandler context) { context.addServlet(CreateExperiment.class, ServerContext.CREATE_EXPERIMENT); context.addServlet(UpdateResults.class, ServerContext.UPDATE_RESULTS); context.addServlet(UpdateRecommendations.class, ServerContext.UPDATE_RECOMMENDATIONS); + context.addServlet(ListRecommendations.class, ServerContext.RECOMMEND_RESULTS); context.addServlet(PerformanceProfileService.class, ServerContext.CREATE_PERF_PROFILE); context.addServlet(PerformanceProfileService.class, ServerContext.LIST_PERF_PROFILES); diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index c10e2fda7..c0d00569b 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -17,6 +17,7 @@ import com.autotune.analyzer.exceptions.KruizeResponse; <<<<<<< HEAD +<<<<<<< HEAD import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.utils.AnalyzerConstants; @@ -29,6 +30,12 @@ import com.autotune.common.data.result.IntervalResults; import com.autotune.common.k8sObjects.K8sObject; >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= +import com.autotune.analyzer.experiment.ExperimentInitiator; +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.common.data.result.ExperimentResultData; +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) import com.autotune.database.service.ExperimentDBService; import com.autotune.utils.KruizeConstants; import com.autotune.utils.Utils; @@ -46,9 +53,13 @@ import java.io.PrintWriter; import java.sql.Timestamp; <<<<<<< HEAD +<<<<<<< HEAD import java.util.Collections; ======= >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= +import java.util.Collections; +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) import java.util.HashMap; import java.util.Map; @@ -77,24 +88,34 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) // Check if experiment_name is provided if (experiment_name == null || experiment_name.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); +<<<<<<< HEAD <<<<<<< HEAD return; ======= >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= + return; +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) } // Check if interval_end_time is provided if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) return; } LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr); +<<<<<<< HEAD ======= } >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) // Convert interval_endtime to UTC date format if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { sendErrorResponse( @@ -103,14 +124,19 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) HttpServletResponse.SC_BAD_REQUEST, String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) ); +<<<<<<< HEAD <<<<<<< HEAD return; ======= >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= + return; +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) } //Check if data exist Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); +<<<<<<< HEAD <<<<<<< HEAD ExperimentResultData experimentResultData = null; try { @@ -143,25 +169,34 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } ======= boolean dataExists = false; +======= + ExperimentResultData experimentResultData = null; +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) try { - dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); } catch (Exception e) { sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + return; } - if (dataExists) { + if (null != experimentResultData) { //Load KruizeObject and generate recommendation Map mainKruizeExperimentMAP = new HashMap<>(); try { - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { - for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { - for (IntervalResults result : containerData.getResults().values()) { - - } - } + // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time + long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); + Timestamp interval_start_time = new Timestamp(subtractedTime); + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); + boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + if (!recommendationCheck) + LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", + experimentResultData.getExperiment_name(), + experimentResultData.getIntervalEndTime()); + else { + new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); } +<<<<<<< HEAD // List experimentResultDataList = ; // boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); // if (!recommendationCheck) @@ -172,11 +207,14 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) // new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); // } >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) } catch (Exception e) { e.printStackTrace(); } } else { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); +<<<<<<< HEAD <<<<<<< HEAD return; } @@ -184,6 +222,10 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } sendSuccessResponse(response, "All ok"); >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= + return; + } +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) } private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { @@ -204,9 +246,12 @@ public void sendErrorResponse(HttpServletResponse response, Exception e, int htt if (null != e) { LOGGER.error(e.toString()); <<<<<<< HEAD +<<<<<<< HEAD ======= e.printStackTrace(); >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) +======= +>>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) if (null == errorMsg) errorMsg = e.getMessage(); } response.sendError(httpStatusCode, errorMsg); diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index aa92f3ca1..0b18ac613 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -63,5 +63,4 @@ public interface ExperimentDAO { // Get KruizeResult Record List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; - } diff --git a/src/main/java/com/autotune/utils/Utils.java b/src/main/java/com/autotune/utils/Utils.java index 2a0321b08..2d5e232f7 100644 --- a/src/main/java/com/autotune/utils/Utils.java +++ b/src/main/java/com/autotune/utils/Utils.java @@ -235,6 +235,7 @@ public static Timestamp getTimeStampFrom(String format, String date) { // Convert the timestamp to UTC Instant desiredInstant = localDateTime.toInstant(ZoneOffset.UTC); Timestamp convertedDate = Timestamp.from(desiredInstant); + return convertedDate; } catch (Exception e) { From e9b0dee84907a7ba8e10f99b311aac47d38e0abd Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 26 May 2023 20:32:47 +0530 Subject: [PATCH 28/61] Added exception conditions. Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/services/UpdateRecommendation.java | 4 ++++ .../com/autotune/database/service/ExperimentDBService.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index c0d00569b..bdbace0c7 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -33,6 +33,7 @@ ======= import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ExperimentResultData; >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) @@ -166,6 +167,7 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) else { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerConstants.RecommendationNotificationMsgConstant.NOT_ENOUGH_DATA); } +<<<<<<< HEAD } ======= boolean dataExists = false; @@ -195,6 +197,8 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) else { new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); +======= +>>>>>>> 88f25571 (Added exception conditions.) } <<<<<<< HEAD // List experimentResultDataList = ; diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index b76d481ab..a8b0a4f13 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -215,6 +215,7 @@ public List addResultsToDB(List re return failedUpdateResultsAPIObjects; } + public ValidationOutputData addRecommendationToDB(Map experimentsMap, List experimentResultDataList) { ValidationOutputData validationOutputData = new ValidationOutputData(false, "", null); if (null == experimentResultDataList) { @@ -224,6 +225,7 @@ public ValidationOutputData addRecommendationToDB(Map expe 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())) { LOGGER.error("Trying to locate Recommendation for non existent experiment: " + From 04b3a9f0164e3cdafb07a051c2b8c5c97c1875cf Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 11:13:32 +0530 Subject: [PATCH 29/61] Merging confilts Signed-off-by: msvinaykumar --- src/main/java/com/autotune/analyzer/Analyzer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/Analyzer.java b/src/main/java/com/autotune/analyzer/Analyzer.java index 52fd1d536..b8c9ee2c5 100644 --- a/src/main/java/com/autotune/analyzer/Analyzer.java +++ b/src/main/java/com/autotune/analyzer/Analyzer.java @@ -48,7 +48,6 @@ public static void addServlets(ServletContextHandler context) { context.addServlet(CreateExperiment.class, ServerContext.CREATE_EXPERIMENT); context.addServlet(UpdateResults.class, ServerContext.UPDATE_RESULTS); context.addServlet(UpdateRecommendations.class, ServerContext.UPDATE_RECOMMENDATIONS); - context.addServlet(ListRecommendations.class, ServerContext.RECOMMEND_RESULTS); context.addServlet(PerformanceProfileService.class, ServerContext.CREATE_PERF_PROFILE); context.addServlet(PerformanceProfileService.class, ServerContext.LIST_PERF_PROFILES); From dec3c9d1a62e89b72c3ac431efa5dfe303abf63a Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 14:49:48 +0530 Subject: [PATCH 30/61] Taking care of duplicate entry to recommendation table Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAO.java | 2 ++ .../java/com/autotune/database/service/ExperimentDBService.java | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 0b18ac613..4778f639e 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -54,9 +54,11 @@ public interface ExperimentDAO { // 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/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index a8b0a4f13..091551b80 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -225,7 +225,6 @@ public ValidationOutputData addRecommendationToDB(Map expe 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())) { LOGGER.error("Trying to locate Recommendation for non existent experiment: " + From b1d1eedf5fd6b4998d466f82b480403c30c63d61 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 6 Jun 2023 16:59:17 +0530 Subject: [PATCH 31/61] resolving conflicts Signed-off-by: msvinaykumar --- .../autotune/analyzer/experiment/ExperimentResultValidation.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java index 4c15404fb..dd6b6cfa6 100644 --- a/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java +++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java @@ -24,6 +24,7 @@ public class ExperimentResultValidation { private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentResultValidation.class); + } From e4a0db99cde6a1bd754348154433499dac63f390 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 12 Jun 2023 21:00:27 +0530 Subject: [PATCH 32/61] Moved logic to select results into perfProfiles. Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/services/UpdateRecommendations.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index 5ade30fad..4964e85b9 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -174,6 +174,7 @@ 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; From 9689644531c83a4ed4bbc874b8b3bc72f3f198a3 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 19 Jun 2023 15:58:41 +0530 Subject: [PATCH 33/61] Date range update recommendations are handled Signed-off-by: msvinaykumar --- .../java/com/autotune/database/service/ExperimentDBService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 091551b80..b76d481ab 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -215,7 +215,6 @@ public List addResultsToDB(List re return failedUpdateResultsAPIObjects; } - public ValidationOutputData addRecommendationToDB(Map experimentsMap, List experimentResultDataList) { ValidationOutputData validationOutputData = new ValidationOutputData(false, "", null); if (null == experimentResultDataList) { From dd69e0e6e4c0e6b233ce65f6608ecd7961c44117 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 34/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index bdbace0c7..d4f215f50 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -18,17 +18,21 @@ import com.autotune.analyzer.exceptions.KruizeResponse; <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ExperimentResultData; ======= +======= +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ContainerData; import com.autotune.common.data.result.IntervalResults; import com.autotune.common.k8sObjects.K8sObject; +<<<<<<< HEAD >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) ======= import com.autotune.analyzer.experiment.ExperimentInitiator; @@ -37,6 +41,8 @@ import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ExperimentResultData; >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) import com.autotune.database.service.ExperimentDBService; import com.autotune.utils.KruizeConstants; import com.autotune.utils.Utils; @@ -55,12 +61,15 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) import java.sql.Timestamp; <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD import java.util.Collections; ======= >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) ======= import java.util.Collections; >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) import java.util.HashMap; import java.util.Map; @@ -90,6 +99,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) if (experiment_name == null || experiment_name.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD return; ======= @@ -97,6 +107,8 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) ======= return; >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) } // Check if interval_end_time is provided @@ -104,6 +116,7 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) return; @@ -117,6 +130,10 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) ======= >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= + } + +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) // Convert interval_endtime to UTC date format if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { sendErrorResponse( @@ -126,6 +143,7 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) ); <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD return; ======= @@ -133,11 +151,14 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= return; >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) } //Check if data exist Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD ExperimentResultData experimentResultData = null; try { @@ -201,6 +222,28 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) >>>>>>> 88f25571 (Added exception conditions.) } <<<<<<< HEAD +======= + boolean dataExists = false; + try { + dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + } catch (Exception e) { + sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + + if (dataExists) { + //Load KruizeObject and generate recommendation + Map mainKruizeExperimentMAP = new HashMap<>(); + try { + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); + KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { + for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { + for (IntervalResults result : containerData.getResults().values()) { + + } + } + } +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) // List experimentResultDataList = ; // boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); // if (!recommendationCheck) @@ -210,15 +253,19 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) // else { // new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); // } +<<<<<<< HEAD >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) ======= >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) } catch (Exception e) { e.printStackTrace(); } } else { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD return; } @@ -230,6 +277,10 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) return; } >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= + } + sendSuccessResponse(response, "All ok"); +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) } private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { @@ -251,11 +302,15 @@ public void sendErrorResponse(HttpServletResponse response, Exception e, int htt LOGGER.error(e.toString()); <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= e.printStackTrace(); >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) ======= >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= + e.printStackTrace(); +>>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) if (null == errorMsg) errorMsg = e.getMessage(); } response.sendError(httpStatusCode, errorMsg); From 2e704759169906659a764bb338b83322e6b19863 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 20 May 2023 21:41:51 +0530 Subject: [PATCH 35/61] UpdateRecommendation API E2E working code is ready. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 65 ++++++++++++++++--- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index d4f215f50..06d02fdc0 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -19,6 +19,7 @@ <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.utils.AnalyzerConstants; @@ -43,6 +44,12 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= +import com.autotune.analyzer.experiment.ExperimentInitiator; +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.common.data.result.ExperimentResultData; +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) import com.autotune.database.service.ExperimentDBService; import com.autotune.utils.KruizeConstants; import com.autotune.utils.Utils; @@ -62,6 +69,7 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD import java.util.Collections; ======= >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) @@ -70,6 +78,9 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= +import java.util.Collections; +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) import java.util.HashMap; import java.util.Map; @@ -100,6 +111,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD return; ======= @@ -109,6 +121,9 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= + return; +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) } // Check if interval_end_time is provided @@ -117,13 +132,17 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) +======= +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) return; } LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr); <<<<<<< HEAD +<<<<<<< HEAD ======= } @@ -134,6 +153,8 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) } >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) // Convert interval_endtime to UTC date format if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { sendErrorResponse( @@ -144,6 +165,7 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ); <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD return; ======= @@ -153,12 +175,16 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= + return; +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) } //Check if data exist Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD ExperimentResultData experimentResultData = null; try { @@ -224,25 +250,34 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) <<<<<<< HEAD ======= boolean dataExists = false; +======= + ExperimentResultData experimentResultData = null; +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) try { - dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); } catch (Exception e) { sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + return; } - if (dataExists) { + if (null != experimentResultData) { //Load KruizeObject and generate recommendation Map mainKruizeExperimentMAP = new HashMap<>(); try { - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { - for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { - for (IntervalResults result : containerData.getResults().values()) { - - } - } + // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time + long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); + Timestamp interval_start_time = new Timestamp(subtractedTime); + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); + boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + if (!recommendationCheck) + LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", + experimentResultData.getExperiment_name(), + experimentResultData.getIntervalEndTime()); + else { + new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); } +<<<<<<< HEAD >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) // List experimentResultDataList = ; // boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); @@ -259,6 +294,8 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) } catch (Exception e) { e.printStackTrace(); } @@ -266,6 +303,7 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD return; } @@ -281,6 +319,10 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) } sendSuccessResponse(response, "All ok"); >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= + return; + } +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) } private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { @@ -303,6 +345,7 @@ public void sendErrorResponse(HttpServletResponse response, Exception e, int htt <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= e.printStackTrace(); >>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) @@ -311,6 +354,8 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= e.printStackTrace(); >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) +======= +>>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) if (null == errorMsg) errorMsg = e.getMessage(); } response.sendError(httpStatusCode, errorMsg); From 26af430f8f81350781485a34e08b06bcfd7176fc Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 26 May 2023 20:32:47 +0530 Subject: [PATCH 36/61] Added exception conditions. Signed-off-by: msvinaykumar --- .../autotune/analyzer/services/UpdateRecommendation.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index 06d02fdc0..cf3ff8c0e 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -47,6 +47,7 @@ >>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) ======= import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.common.data.result.ExperimentResultData; >>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) @@ -274,8 +275,12 @@ >>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) experimentResultData.getExperiment_name(), experimentResultData.getIntervalEndTime()); else { - new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); + boolean success = new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + if (success) + sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); + else { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerConstants.RecommendationNotificationMsgConstant.NOT_ENOUGH_DATA); + } } <<<<<<< HEAD >>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) From e8b7c3c49389605c9ca72f0c47bc77700a8c6c5b Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 27 May 2023 15:22:49 +0530 Subject: [PATCH 37/61] To restrict the number of rows in the result set, the Load results operation involves locating the appropriate method and configuring the desired limitation. It's important to note that in order for the Limit rows feature to function correctly, the CreateExperiment API must adhere strictly to the trail settings' measurement duration and should not allow arbitrary values Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 368 ------------------ 1 file changed, 368 deletions(-) delete mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java deleted file mode 100644 index cf3ff8c0e..000000000 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ /dev/null @@ -1,368 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022 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.services; - -import com.autotune.analyzer.exceptions.KruizeResponse; -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -import com.autotune.analyzer.experiment.ExperimentInitiator; -import com.autotune.analyzer.kruizeObject.KruizeObject; -import com.autotune.analyzer.utils.AnalyzerConstants; -import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ExperimentResultData; -======= -======= ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -import com.autotune.analyzer.kruizeObject.KruizeObject; -import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ContainerData; -import com.autotune.common.data.result.IntervalResults; -import com.autotune.common.k8sObjects.K8sObject; -<<<<<<< HEAD ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= -import com.autotune.analyzer.experiment.ExperimentInitiator; -import com.autotune.analyzer.kruizeObject.KruizeObject; -import com.autotune.analyzer.utils.AnalyzerConstants; -import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ExperimentResultData; ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= -import com.autotune.analyzer.experiment.ExperimentInitiator; -import com.autotune.analyzer.kruizeObject.KruizeObject; -import com.autotune.analyzer.utils.AnalyzerConstants; -import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ExperimentResultData; ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) -import com.autotune.database.service.ExperimentDBService; -import com.autotune.utils.KruizeConstants; -import com.autotune.utils.Utils; -import com.google.gson.Gson; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.sql.Timestamp; -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -import java.util.Collections; -======= ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= -import java.util.Collections; ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= -import java.util.Collections; ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) -import java.util.HashMap; -import java.util.Map; - -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; - -/** - * - */ -@WebServlet(asyncSupported = true) -public class UpdateRecommendation extends HttpServlet { - private static final long serialVersionUID = 1L; - private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // 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); - - // Check if experiment_name is provided - if (experiment_name == null || experiment_name.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - return; -======= ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= - return; ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= - return; ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - } - - // Check if interval_end_time is provided - if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -======= ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - return; - } - - LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr); -<<<<<<< HEAD -<<<<<<< HEAD -======= - } - ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= - } - ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - // Convert interval_endtime to UTC date format - if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { - sendErrorResponse( - response, - new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), - HttpServletResponse.SC_BAD_REQUEST, - String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) - ); -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - return; -======= ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= - return; ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= - return; ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - } - - //Check if data exist - Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - ExperimentResultData experimentResultData = null; - try { - experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); - } catch (Exception e) { - sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - return; - } - - if (null != experimentResultData) { - //Load KruizeObject and generate recommendation - Map mainKruizeExperimentMAP = new HashMap<>(); - try { - // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time - long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); - Timestamp interval_start_time = new Timestamp(subtractedTime); - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); - boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - if (!recommendationCheck) - LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", - experimentResultData.getExperiment_name(), - experimentResultData.getIntervalEndTime()); - else { - boolean success = new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - if (success) - sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); - else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerConstants.RecommendationNotificationMsgConstant.NOT_ENOUGH_DATA); - } -<<<<<<< HEAD - } -======= - boolean dataExists = false; -======= - ExperimentResultData experimentResultData = null; ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) - try { - experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); - } catch (Exception e) { - sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - return; - } - - if (null != experimentResultData) { - //Load KruizeObject and generate recommendation - Map mainKruizeExperimentMAP = new HashMap<>(); - try { - // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time - long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); - Timestamp interval_start_time = new Timestamp(subtractedTime); - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); - boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - if (!recommendationCheck) - LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", - experimentResultData.getExperiment_name(), - experimentResultData.getIntervalEndTime()); - else { - new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); -======= ->>>>>>> 88f25571 (Added exception conditions.) - } -<<<<<<< HEAD -======= - boolean dataExists = false; -======= - ExperimentResultData experimentResultData = null; ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - try { - experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); - } catch (Exception e) { - sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - return; - } - - if (null != experimentResultData) { - //Load KruizeObject and generate recommendation - Map mainKruizeExperimentMAP = new HashMap<>(); - try { - // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time - long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); - Timestamp interval_start_time = new Timestamp(subtractedTime); - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); - boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - if (!recommendationCheck) - LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", - experimentResultData.getExperiment_name(), - experimentResultData.getIntervalEndTime()); - else { - boolean success = new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - if (success) - sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); - else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerConstants.RecommendationNotificationMsgConstant.NOT_ENOUGH_DATA); - } - } -<<<<<<< HEAD ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -// List experimentResultDataList = ; -// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); -// if (!recommendationCheck) -// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", -// experimentResultDataList.get(0).getExperiment_name(), -// experimentResultDataList.get(0).getIntervalEndTime()); -// else { -// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); -// } -<<<<<<< HEAD ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - } catch (Exception e) { - e.printStackTrace(); - } - } else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - return; - } -======= - } - sendSuccessResponse(response, "All ok"); ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= - return; - } ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= - } - sendSuccessResponse(response, "All ok"); ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= - return; - } ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - } - - private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { - response.setContentType(JSON_CONTENT_TYPE); - response.setCharacterEncoding(CHARACTER_ENCODING); - response.setStatus(HttpServletResponse.SC_CREATED); - PrintWriter out = response.getWriter(); - out.append( - new Gson().toJson( - new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") - ) - ); - out.flush(); - } - - public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws - IOException { - if (null != e) { - LOGGER.error(e.toString()); -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -======= - e.printStackTrace(); ->>>>>>> 93d3e5f7 (In progress code checked in for updateRecommendation API.) -======= ->>>>>>> b0ef3a73 (UpdateRecommendation API E2E working code is ready.) -======= - e.printStackTrace(); ->>>>>>> 89b4c960 (In progress code checked in for updateRecommendation API.) -======= ->>>>>>> a670b8f5 (UpdateRecommendation API E2E working code is ready.) - if (null == errorMsg) errorMsg = e.getMessage(); - } - response.sendError(httpStatusCode, errorMsg); - } -} From 2dfc303f2067b602118d5a128b12eecce04f5323 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 20 Jul 2023 20:44:48 +0530 Subject: [PATCH 38/61] endDate is not mandatory Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/services/UpdateRecommendations.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index 4964e85b9..5ade30fad 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -174,7 +174,6 @@ 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; From 57b33cdb6c37f1cee334c09d9f669bf9f88c1abb Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 39/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAO.java | 4 +++- src/main/java/com/autotune/database/helper/DBConstants.java | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 4778f639e..535297458 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -49,7 +49,9 @@ 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; + + List loadResultsByExperimentName(String experimentName, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; + // Load all recommendations of a particular experiment List loadRecommendationsByExperimentName(String experimentName) throws Exception; diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index 251f74b02..165a52a71 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -13,6 +13,7 @@ public static final class SQLQUERY { 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"; From eee8dbc30101b87f3d927604c2d27c88e65574fd Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 20 May 2023 21:41:51 +0530 Subject: [PATCH 40/61] UpdateRecommendation API E2E working code is ready. Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAO.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 535297458..56b7595ad 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -67,4 +67,5 @@ public interface ExperimentDAO { // Get KruizeResult Record List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; + } From 0f91741f924b397f5bd0bfbe78e36cceb6b8c9c1 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 26 May 2023 20:32:47 +0530 Subject: [PATCH 41/61] Added exception conditions. Signed-off-by: msvinaykumar --- .../java/com/autotune/database/service/ExperimentDBService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index b76d481ab..091551b80 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -215,6 +215,7 @@ public List addResultsToDB(List re return failedUpdateResultsAPIObjects; } + public ValidationOutputData addRecommendationToDB(Map experimentsMap, List experimentResultDataList) { ValidationOutputData validationOutputData = new ValidationOutputData(false, "", null); if (null == experimentResultDataList) { From c05376181cb0ab2211bb4a28af4d3e6f2342be49 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 27 May 2023 15:22:49 +0530 Subject: [PATCH 42/61] To restrict the number of rows in the result set, the Load results operation involves locating the appropriate method and configuring the desired limitation. It's important to note that in order for the Limit rows feature to function correctly, the CreateExperiment API must adhere strictly to the trail settings' measurement duration and should not allow arbitrary values Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAO.java | 2 -- src/main/java/com/autotune/database/helper/DBConstants.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 56b7595ad..088eab248 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -49,10 +49,8 @@ public interface ExperimentDAO { List loadExperimentByName(String experimentName) throws Exception; // Load all results for a particular experimentName - List loadResultsByExperimentName(String experimentName, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; - // Load all recommendations of a particular experiment List loadRecommendationsByExperimentName(String experimentName) throws Exception; diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index 165a52a71..251f74b02 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -13,7 +13,6 @@ public static final class SQLQUERY { 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"; From 801835c12beda0cbbf5ea7f95a220ec1ca419c74 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 11:13:32 +0530 Subject: [PATCH 43/61] Merging confilts Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/services/UpdateRecommendations.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index 5ade30fad..13ba9fd22 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -149,7 +149,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) return; } - if (experimentResultDataList.size() > 0) { //Load KruizeObject and generate recommendation From 6b787d2e0290010032288c863cd9891f71fb785e Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 14:49:48 +0530 Subject: [PATCH 44/61] Taking care of duplicate entry to recommendation table Signed-off-by: msvinaykumar --- src/main/java/com/autotune/analyzer/services/UpdateResults.java | 1 + .../com/autotune/analyzer/utils/AnalyzerErrorConstants.java | 1 - src/main/java/com/autotune/database/dao/ExperimentDAO.java | 2 -- .../java/com/autotune/database/service/ExperimentDBService.java | 2 -- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index a150bae51..99ddfa921 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -67,6 +67,7 @@ public void init(ServletConfig config) throws ServletException { 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); diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java index 7c145bade..802c92338 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -153,7 +153,6 @@ public static final class KruizeRecommendationError { private KruizeRecommendationError() { - } } } diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 088eab248..2880d63da 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -54,11 +54,9 @@ public interface ExperimentDAO { // 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/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 091551b80..b950dac18 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -54,7 +54,6 @@ public ExperimentDBService() { this.experimentDAO = new ExperimentDAOImpl(); } - public void loadAllExperiments(Map mainKruizeExperimentMap) throws Exception { ExperimentInterface experimentInterface = new ExperimentInterfaceImpl(); List entries = experimentDAO.loadAllExperiments(); @@ -215,7 +214,6 @@ public List addResultsToDB(List re return failedUpdateResultsAPIObjects; } - public ValidationOutputData addRecommendationToDB(Map experimentsMap, List experimentResultDataList) { ValidationOutputData validationOutputData = new ValidationOutputData(false, "", null); if (null == experimentResultDataList) { From b4ca2b6f4e350a5a777fdf5ec2bb87cda746a1e2 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 6 Jun 2023 16:59:17 +0530 Subject: [PATCH 45/61] resolving conflicts Signed-off-by: msvinaykumar --- .../autotune/analyzer/experiment/ExperimentResultValidation.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java index dd6b6cfa6..4c15404fb 100644 --- a/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java +++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentResultValidation.java @@ -24,7 +24,6 @@ public class ExperimentResultValidation { private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentResultValidation.class); - } From 198417f1706a5eb1c823863fbaf347d662c3bafe Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 12 Jun 2023 21:00:27 +0530 Subject: [PATCH 46/61] Moved logic to select results into perfProfiles. Signed-off-by: msvinaykumar --- .../com/autotune/analyzer/experiment/ExperimentInitiator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java index c114a9819..8247c11ba 100644 --- a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java +++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java @@ -93,6 +93,7 @@ public void generateAndAddRecommendations(KruizeObject kruizeObject, List updateResultsAPIObjects) { List failedDBObjects = new ArrayList<>(); Validator validator = Validation.byProvider(HibernateValidator.class) From 7ab4feea36be7f65b46f8bd5c65e6b06ca0c2358 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 20 May 2023 21:41:51 +0530 Subject: [PATCH 47/61] UpdateRecommendation API E2E working code is ready. Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAO.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 2880d63da..bb414b9e4 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -54,6 +54,7 @@ public interface ExperimentDAO { // Load all recommendations of a particular experiment List loadRecommendationsByExperimentName(String experimentName) throws Exception; +<<<<<<< HEAD // Load a single Performance Profile based on name List loadPerformanceProfileByName(String performanceProfileName) throws Exception; From e9873e952638db239024aefa1a359991b42e456b Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 26 May 2023 20:32:47 +0530 Subject: [PATCH 48/61] Added exception conditions. Signed-off-by: msvinaykumar --- .../java/com/autotune/database/service/ExperimentDBService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index b950dac18..454a93f73 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -214,6 +214,7 @@ public List addResultsToDB(List re return failedUpdateResultsAPIObjects; } + public ValidationOutputData addRecommendationToDB(Map experimentsMap, List experimentResultDataList) { ValidationOutputData validationOutputData = new ValidationOutputData(false, "", null); if (null == experimentResultDataList) { @@ -223,6 +224,7 @@ public ValidationOutputData addRecommendationToDB(Map expe 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())) { LOGGER.error("Trying to locate Recommendation for non existent experiment: " + From 209e8f194abd9835649d957aa585ee6fc793fd2d Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 27 May 2023 15:22:49 +0530 Subject: [PATCH 49/61] To restrict the number of rows in the result set, the Load results operation involves locating the appropriate method and configuring the desired limitation. It's important to note that in order for the Limit rows feature to function correctly, the CreateExperiment API must adhere strictly to the trail settings' measurement duration and should not allow arbitrary values Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index bb414b9e4..80b655e3d 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -49,7 +49,7 @@ public interface ExperimentDAO { List loadExperimentByName(String experimentName) throws Exception; // Load all results for a particular experimentName - List loadResultsByExperimentName(String experimentName, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; + 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; From 9dbb7da50e955e3c3973ac42afa7de88f42fb717 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 14:49:48 +0530 Subject: [PATCH 50/61] Taking care of duplicate entry to recommendation table Signed-off-by: msvinaykumar --- .../java/com/autotune/analyzer/services/UpdateResults.java | 1 + .../com/autotune/analyzer/utils/AnalyzerErrorConstants.java | 1 + src/main/java/com/autotune/database/dao/ExperimentDAO.java | 3 ++- .../com/autotune/database/service/ExperimentDBService.java | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 99ddfa921..8267eed06 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -88,6 +88,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) 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 { + sendSuccessResponse(response, AnalyzerConstants.ServiceConstants.RESULT_SAVED); } } catch (Exception e) { diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java index 802c92338..7c145bade 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -153,6 +153,7 @@ public static final class KruizeRecommendationError { private KruizeRecommendationError() { + } } } diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 80b655e3d..ed17756b0 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -54,10 +54,11 @@ public interface ExperimentDAO { // Load all recommendations of a particular experiment List loadRecommendationsByExperimentName(String experimentName) throws Exception; -<<<<<<< HEAD + // 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/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 454a93f73..111d04096 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -225,6 +225,7 @@ public ValidationOutputData addRecommendationToDB(Map expe } 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())) { LOGGER.error("Trying to locate Recommendation for non existent experiment: " + @@ -345,6 +346,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); From 59d6cd5a2d42ae904f5c0e2cad2cf0734362a9df Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 23 May 2023 12:51:53 +0530 Subject: [PATCH 51/61] UpdateResults API optimized. Signed-off-by: msvinaykumar --- src/main/java/com/autotune/analyzer/services/UpdateResults.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 8267eed06..99ddfa921 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -88,7 +88,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) 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 { - sendSuccessResponse(response, AnalyzerConstants.ServiceConstants.RESULT_SAVED); } } catch (Exception e) { From 0da8d1f87aed7682086fb920dbc60179bdeb421b Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 18 May 2023 17:12:02 +0530 Subject: [PATCH 52/61] In progress code checked in for updateRecommendation API. Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 147 ++++++++++++++++++ .../autotune/database/dao/ExperimentDAO.java | 5 +- src/main/java/com/autotune/utils/Utils.java | 1 + 3 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java new file mode 100644 index 000000000..b5dbed42f --- /dev/null +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2022 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.services; + +import com.autotune.analyzer.exceptions.KruizeResponse; +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.common.data.result.ContainerData; +import com.autotune.common.data.result.IntervalResults; +import com.autotune.common.k8sObjects.K8sObject; +import com.autotune.database.service.ExperimentDBService; +import com.autotune.utils.KruizeConstants; +import com.autotune.utils.Utils; +import com.google.gson.Gson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.Map; + +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; +import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; + +/** + * + */ +@WebServlet(asyncSupported = true) +public class UpdateRecommendation extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // 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); + + // Check if experiment_name is provided + if (experiment_name == null || experiment_name.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); + } + + // Check if interval_end_time is provided + if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); + } + + // Convert interval_endtime to UTC date format + if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { + sendErrorResponse( + response, + new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), + HttpServletResponse.SC_BAD_REQUEST, + String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) + ); + } + + //Check if data exist + Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); + boolean dataExists = false; + try { + dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + } catch (Exception e) { + sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + + if (dataExists) { + //Load KruizeObject and generate recommendation + Map mainKruizeExperimentMAP = new HashMap<>(); + try { + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); + KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { + for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { + for (IntervalResults result : containerData.getResults().values()) { + + } + } + } +// List experimentResultDataList = ; +// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); +// if (!recommendationCheck) +// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", +// experimentResultDataList.get(0).getExperiment_name(), +// experimentResultDataList.get(0).getIntervalEndTime()); +// else { +// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); +// } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); + } + sendSuccessResponse(response, "All ok"); + } + + private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { + response.setContentType(JSON_CONTENT_TYPE); + response.setCharacterEncoding(CHARACTER_ENCODING); + response.setStatus(HttpServletResponse.SC_CREATED); + PrintWriter out = response.getWriter(); + out.append( + new Gson().toJson( + new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") + ) + ); + out.flush(); + } + + public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws + IOException { + if (null != e) { + LOGGER.error(e.toString()); + e.printStackTrace(); + if (null == errorMsg) errorMsg = e.getMessage(); + } + response.sendError(httpStatusCode, errorMsg); + } +} diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index ed17756b0..da0423d89 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -49,12 +49,13 @@ 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; + + List loadResultsByExperimentName(String experimentName, Timestamp interval_start_time, Timestamp interval_end_time) 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; diff --git a/src/main/java/com/autotune/utils/Utils.java b/src/main/java/com/autotune/utils/Utils.java index 2d5e232f7..bed891eb3 100644 --- a/src/main/java/com/autotune/utils/Utils.java +++ b/src/main/java/com/autotune/utils/Utils.java @@ -238,6 +238,7 @@ public static Timestamp getTimeStampFrom(String format, String date) { return convertedDate; + } catch (Exception e) { return null; } From a9785e1d92e60631467a8e929213e9a57ca1dcd7 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 20 May 2023 21:41:51 +0530 Subject: [PATCH 53/61] UpdateRecommendation API E2E working code is ready. Signed-off-by: msvinaykumar --- .../java/com/autotune/analyzer/Analyzer.java | 1 + .../services/UpdateRecommendation.java | 49 +++++++++---------- .../autotune/database/dao/ExperimentDAO.java | 1 + src/main/java/com/autotune/utils/Utils.java | 1 - 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/Analyzer.java b/src/main/java/com/autotune/analyzer/Analyzer.java index b8c9ee2c5..52fd1d536 100644 --- a/src/main/java/com/autotune/analyzer/Analyzer.java +++ b/src/main/java/com/autotune/analyzer/Analyzer.java @@ -48,6 +48,7 @@ public static void addServlets(ServletContextHandler context) { context.addServlet(CreateExperiment.class, ServerContext.CREATE_EXPERIMENT); context.addServlet(UpdateResults.class, ServerContext.UPDATE_RESULTS); context.addServlet(UpdateRecommendations.class, ServerContext.UPDATE_RECOMMENDATIONS); + context.addServlet(ListRecommendations.class, ServerContext.RECOMMEND_RESULTS); context.addServlet(PerformanceProfileService.class, ServerContext.CREATE_PERF_PROFILE); context.addServlet(PerformanceProfileService.class, ServerContext.LIST_PERF_PROFILES); diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index b5dbed42f..ea05c2493 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -16,11 +16,10 @@ package com.autotune.analyzer.services; import com.autotune.analyzer.exceptions.KruizeResponse; +import com.autotune.analyzer.experiment.ExperimentInitiator; import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ContainerData; -import com.autotune.common.data.result.IntervalResults; -import com.autotune.common.k8sObjects.K8sObject; +import com.autotune.common.data.result.ExperimentResultData; import com.autotune.database.service.ExperimentDBService; import com.autotune.utils.KruizeConstants; import com.autotune.utils.Utils; @@ -37,6 +36,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.sql.Timestamp; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -65,13 +65,16 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) // Check if experiment_name is provided if (experiment_name == null || experiment_name.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); + return; } // Check if interval_end_time is provided if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); + return; } + LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr); // Convert interval_endtime to UTC date format if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { sendErrorResponse( @@ -80,46 +83,43 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) HttpServletResponse.SC_BAD_REQUEST, String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) ); + return; } //Check if data exist Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); - boolean dataExists = false; + ExperimentResultData experimentResultData = null; try { - dataExists = new ExperimentDBService().checkIfResultsExists(experiment_name, interval_end_time); + experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); } catch (Exception e) { sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + return; } - if (dataExists) { + if (null != experimentResultData) { //Load KruizeObject and generate recommendation Map mainKruizeExperimentMAP = new HashMap<>(); try { - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, null, interval_end_time); - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - for (K8sObject k8Obj : kruizeObject.getKubernetes_objects()) { - for (ContainerData containerData : k8Obj.getContainerDataMap().values()) { - for (IntervalResults result : containerData.getResults().values()) { - - } - } + // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time + long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); + Timestamp interval_start_time = new Timestamp(subtractedTime); + new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); + boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + if (!recommendationCheck) + LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", + experimentResultData.getExperiment_name(), + experimentResultData.getIntervalEndTime()); + else { + new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); + sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); } -// List experimentResultDataList = ; -// boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, experimentResultDataList); -// if (!recommendationCheck) -// LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", -// experimentResultDataList.get(0).getExperiment_name(), -// experimentResultDataList.get(0).getIntervalEndTime()); -// else { -// new ExperimentDBService().addRecommendationToDB(mKruizeExperimentMap, experimentResultDataList); -// } } catch (Exception e) { e.printStackTrace(); } } else { sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); + return; } - sendSuccessResponse(response, "All ok"); } private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { @@ -139,7 +139,6 @@ public void sendErrorResponse(HttpServletResponse response, Exception e, int htt IOException { if (null != e) { LOGGER.error(e.toString()); - e.printStackTrace(); if (null == errorMsg) errorMsg = e.getMessage(); } response.sendError(httpStatusCode, errorMsg); diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index da0423d89..56b7595ad 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -56,6 +56,7 @@ public interface ExperimentDAO { // 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; diff --git a/src/main/java/com/autotune/utils/Utils.java b/src/main/java/com/autotune/utils/Utils.java index bed891eb3..2d5e232f7 100644 --- a/src/main/java/com/autotune/utils/Utils.java +++ b/src/main/java/com/autotune/utils/Utils.java @@ -238,7 +238,6 @@ public static Timestamp getTimeStampFrom(String format, String date) { return convertedDate; - } catch (Exception e) { return null; } From 0b8e39b7edcea44906573df012efb3459525b229 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 27 May 2023 15:22:49 +0530 Subject: [PATCH 54/61] To restrict the number of rows in the result set, the Load results operation involves locating the appropriate method and configuring the desired limitation. It's important to note that in order for the Limit rows feature to function correctly, the CreateExperiment API must adhere strictly to the trail settings' measurement duration and should not allow arbitrary values Signed-off-by: msvinaykumar --- .../analyzer/services/UpdateRecommendation.java | 15 +++++++++++---- .../com/autotune/database/dao/ExperimentDAO.java | 3 +-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java index ea05c2493..913642917 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java @@ -100,10 +100,17 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) //Load KruizeObject and generate recommendation Map mainKruizeExperimentMAP = new HashMap<>(); try { - // Subtract LONG_TERM_DURATION_DAYS from the given interval_end_time - long subtractedTime = interval_end_time.getTime() - (KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MILLI_SECONDS_FOR_DAY); - Timestamp interval_start_time = new Timestamp(subtractedTime); - new ExperimentDBService().loadExperimentAndResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_start_time, interval_end_time); + //Load KruizeObject + ExperimentDBService experimentDBService = new ExperimentDBService(); + experimentDBService.loadExperimentFromDBByName(mainKruizeExperimentMAP, experiment_name); + KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + /* + To restrict the number of rows in the result set, the Load results operation involves locating the appropriate method and configuring the desired limitation. + It's important to note that in order for the Limit rows feature to function correctly, + the CreateExperiment API must adhere strictly to the trail settings' measurement duration and should not allow arbitrary values + */ + int limitRows = (int) ((KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MINUTES_FOR_DAY) / kruizeObject.getTrial_settings().getMeasurement_durationMinutes_inDouble()); + experimentDBService.loadResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_end_time, limitRows); boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); if (!recommendationCheck) LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 56b7595ad..558ea6710 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -50,8 +50,7 @@ public interface ExperimentDAO { // Load all results for a particular experimentName - List loadResultsByExperimentName(String experimentName, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; - + 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; From 9be284184870ba3228a78d7151d1d4758806f7c6 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 11:13:32 +0530 Subject: [PATCH 55/61] Merging confilts Signed-off-by: msvinaykumar --- src/main/java/com/autotune/analyzer/Analyzer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/Analyzer.java b/src/main/java/com/autotune/analyzer/Analyzer.java index 52fd1d536..b8c9ee2c5 100644 --- a/src/main/java/com/autotune/analyzer/Analyzer.java +++ b/src/main/java/com/autotune/analyzer/Analyzer.java @@ -48,7 +48,6 @@ public static void addServlets(ServletContextHandler context) { context.addServlet(CreateExperiment.class, ServerContext.CREATE_EXPERIMENT); context.addServlet(UpdateResults.class, ServerContext.UPDATE_RESULTS); context.addServlet(UpdateRecommendations.class, ServerContext.UPDATE_RECOMMENDATIONS); - context.addServlet(ListRecommendations.class, ServerContext.RECOMMEND_RESULTS); context.addServlet(PerformanceProfileService.class, ServerContext.CREATE_PERF_PROFILE); context.addServlet(PerformanceProfileService.class, ServerContext.LIST_PERF_PROFILES); From 676de219859f1947a47e892b3830737e434032fe Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 1 Jun 2023 14:49:48 +0530 Subject: [PATCH 56/61] Taking care of duplicate entry to recommendation table Signed-off-by: msvinaykumar --- .../java/com/autotune/database/service/ExperimentDBService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 111d04096..c394ac70c 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -224,8 +224,6 @@ public ValidationOutputData addRecommendationToDB(Map expe 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())) { LOGGER.error("Trying to locate Recommendation for non existent experiment: " + From d7076123e41998e9b793e5def7ddb361dc1aab0a Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 11 Aug 2023 16:52:39 +0530 Subject: [PATCH 57/61] restricted http request thread to 6 Signed-off-by: msvinaykumar --- src/main/java/com/autotune/Autotune.java | 17 ++++++++++++++--- .../java/com/autotune/utils/ServerContext.java | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) 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/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 From c78abeb498ce290a9f5f02b87e38e1ff0a3140b2 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 11 Aug 2023 18:52:28 +0530 Subject: [PATCH 58/61] resolved conflicts Signed-off-by: msvinaykumar --- src/main/java/com/autotune/analyzer/services/UpdateResults.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 99ddfa921..a150bae51 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -67,7 +67,6 @@ public void init(ServletConfig config) throws ServletException { 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); From f5090a9ddc81a085919e388c80da0ae0cba73668 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 12 Aug 2023 16:56:31 +0530 Subject: [PATCH 59/61] tested hole in results for already updated recommendations fix Signed-off-by: msvinaykumar --- .../ExperimentNameExistValidator.java | 14 +- .../KubernetesElementsValidator.java | 107 ++--- .../PerformanceProfileValidator.java | 4 + .../services/PerformanceProfileService.java | 44 +- .../autotune/database/helper/DBHelpers.java | 413 +----------------- .../autotune/service/InitiateListener.java | 12 +- 6 files changed, 105 insertions(+), 489 deletions(-) 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 index f95df7da5..2e9c64e9a 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java @@ -37,12 +37,14 @@ public class ExperimentNameExistValidator implements ConstraintValidator { private static final Logger LOGGER = LoggerFactory.getLogger(PerformanceProfileValidator.class); @@ -44,6 +47,7 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint */ 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 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/database/helper/DBHelpers.java b/src/main/java/com/autotune/database/helper/DBHelpers.java index 578a0824e..cb7c2c3b6 100644 --- a/src/main/java/com/autotune/database/helper/DBHelpers.java +++ b/src/main/java/com/autotune/database/helper/DBHelpers.java @@ -54,6 +54,7 @@ public class DBHelpers { private static final Logger LOGGER = LoggerFactory.getLogger(DBHelpers.class); + private DBHelpers() { } @@ -242,418 +243,6 @@ private Converters() { } - public static class KruizeObjectConverters { - private KruizeObjectConverters() { - - } - - /** - * @param apiObject - * @return KruizeExperimentEntry - * This methode facilitate to store data into db by accumulating required data from KruizeObject. - */ - public static KruizeExperimentEntry convertCreateAPIObjToExperimentDBObj(CreateExperimentAPIObject apiObject) { - KruizeExperimentEntry kruizeExperimentEntry = null; - try { - kruizeExperimentEntry = new KruizeExperimentEntry(); - kruizeExperimentEntry.setExperiment_name(apiObject.getExperimentName()); - kruizeExperimentEntry.setExperiment_id(Utils.generateID(apiObject)); - kruizeExperimentEntry.setCluster_name(apiObject.getClusterName()); - kruizeExperimentEntry.setMode(apiObject.getMode()); - kruizeExperimentEntry.setPerformance_profile(apiObject.getPerformanceProfile()); - kruizeExperimentEntry.setVersion(apiObject.getApiVersion()); - kruizeExperimentEntry.setTarget_cluster(apiObject.getTargetCluster()); - kruizeExperimentEntry.setStatus(AnalyzerConstants.ExperimentStatus.IN_PROGRESS); - ObjectMapper objectMapper = new ObjectMapper(); - try { - kruizeExperimentEntry.setExtended_data( - objectMapper.readTree( - new Gson().toJson(apiObject) - ) - ); - } catch (JsonProcessingException e) { - throw new Exception("Error while creating Extended data due to : " + e.getMessage()); - } - } catch (Exception e) { - kruizeExperimentEntry = null; - LOGGER.error("Error while converting Kruize Object to experimentDetailTable due to {}", e.getMessage()); - e.printStackTrace(); - } - return kruizeExperimentEntry; - } - - /** - * @param experimentResultData - * @return KruizeResultsEntry - * This methode facilitate to store data into db by accumulating required data from ExperimentResultData. - */ - public static KruizeResultsEntry convertExperimentResultToExperimentResultsTable(ExperimentResultData experimentResultData) { - KruizeResultsEntry kruizeResultsEntry = null; - Gson gson = new GsonBuilder() - .disableHtmlEscaping() - .setPrettyPrinting() - .enableComplexMapKeySerialization() - .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) - .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) - .create(); - try { - kruizeResultsEntry = new KruizeResultsEntry(); - kruizeResultsEntry.setExperiment_name(experimentResultData.getExperiment_name()); - kruizeResultsEntry.setInterval_start_time(experimentResultData.getIntervalStartTime()); - kruizeResultsEntry.setInterval_end_time(experimentResultData.getIntervalEndTime()); - kruizeResultsEntry.setDuration_minutes( - Double.valueOf((experimentResultData.getIntervalEndTime().getTime() - - experimentResultData.getIntervalStartTime().getTime()) / (60 * 1000)) - ); - Map> k8sObjectsMap = Map.of(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS, experimentResultData.getKubernetes_objects()); - String k8sObjectString = gson.toJson(k8sObjectsMap); - ObjectMapper objectMapper = new ObjectMapper(); - try { - kruizeResultsEntry.setExtended_data( - objectMapper.readTree( - k8sObjectString - ) - ); - } catch (JsonProcessingException e) { - throw new Exception("Error while creating Extended data due to : " + e.getMessage()); - } - } catch (Exception e) { - kruizeResultsEntry = null; - LOGGER.error("Error while converting ExperimentResultData to ExperimentResultsTable due to {}", e.getMessage()); - e.printStackTrace(); - } - return kruizeResultsEntry; - } - - public static ListRecommendationsAPIObject getListRecommendationAPIObjectForDB(KruizeObject kruizeObject, Timestamp monitoringEndTime) { - if (null == kruizeObject) - return null; - if (null == monitoringEndTime) - return null; - if (null == kruizeObject.getKubernetes_objects()) - return null; - if (kruizeObject.getKubernetes_objects().isEmpty()) - return null; - List kubernetesAPIObjectList = new ArrayList<>(); - for (K8sObject k8sObject : kruizeObject.getKubernetes_objects()) { - if (null == k8sObject) - continue; - if (null == k8sObject.getContainerDataMap()) - continue; - if (k8sObject.getContainerDataMap().isEmpty()) - continue; - KubernetesAPIObject kubernetesAPIObject = new KubernetesAPIObject(k8sObject.getName(), k8sObject.getType(), k8sObject.getNamespace()); - boolean matchFound = false; - List containerAPIObjectList = new ArrayList<>(); - for (ContainerData containerData : k8sObject.getContainerDataMap().values()) { - ContainerData clonedContainerData = Utils.getClone(containerData, ContainerData.class); - if (null == clonedContainerData.getContainerRecommendations()) - continue; - if (null == clonedContainerData.getContainerRecommendations().getData()) - continue; - if (clonedContainerData.getContainerRecommendations().getData().isEmpty()) - continue; - HashMap>> recommendations - = clonedContainerData.getContainerRecommendations().getData(); - if (null != monitoringEndTime && recommendations.containsKey(monitoringEndTime)) { - matchFound = true; - ContainerAPIObject containerAPIObject = null; - List tempList = new ArrayList<>(); - for (Timestamp timestamp : recommendations.keySet()) { - if (!timestamp.equals(monitoringEndTime)) - tempList.add(timestamp); - } - for (Timestamp timestamp : tempList) { - recommendations.remove(timestamp); - } - clonedContainerData.getContainerRecommendations().setData(recommendations); - containerAPIObject = new ContainerAPIObject(clonedContainerData.getContainer_name(), - clonedContainerData.getContainer_image_name(), - clonedContainerData.getContainerRecommendations(), - null); - containerAPIObjectList.add(containerAPIObject); - } - } - kubernetesAPIObject.setContainerAPIObjects(containerAPIObjectList); - if (matchFound) { - kubernetesAPIObjectList.add(kubernetesAPIObject); - } - } - ListRecommendationsAPIObject listRecommendationsAPIObject = null; - if (!kubernetesAPIObjectList.isEmpty()) { - listRecommendationsAPIObject = new ListRecommendationsAPIObject(); - listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); - listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); - listRecommendationsAPIObject.setKubernetesObjects(kubernetesAPIObjectList); - } - return listRecommendationsAPIObject; - } - - public static KruizeRecommendationEntry convertKruizeObjectTORecommendation(KruizeObject kruizeObject, ExperimentResultData experimentResultData) { - KruizeRecommendationEntry kruizeRecommendationEntry = null; - Timestamp monitoringEndTime = null; - Boolean checkForTimestamp = false; - Boolean getLatest = true; - Gson gson = new GsonBuilder() - .disableHtmlEscaping() - .setPrettyPrinting() - .enableComplexMapKeySerialization() - .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) - .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) - .create(); - try { - if (null != experimentResultData) { - monitoringEndTime = experimentResultData.getIntervalEndTime(); - } - ListRecommendationsAPIObject listRecommendationsAPIObject = getListRecommendationAPIObjectForDB( - kruizeObject, monitoringEndTime); - if (null == listRecommendationsAPIObject) { - return null; - } - LOGGER.debug(new GsonBuilder().setPrettyPrinting().create().toJson(listRecommendationsAPIObject)); - kruizeRecommendationEntry = new KruizeRecommendationEntry(); - kruizeRecommendationEntry.setExperiment_name(listRecommendationsAPIObject.getExperimentName()); - kruizeRecommendationEntry.setCluster_name(listRecommendationsAPIObject.getClusterName()); - Timestamp endInterval = null; - // todo : what happens if two k8 objects or Containers with different timestamp - for (KubernetesAPIObject k8sObject : listRecommendationsAPIObject.getKubernetesObjects()) { - for (ContainerAPIObject containerAPIObject : k8sObject.getContainerAPIObjects()) { - endInterval = containerAPIObject.getContainerRecommendations().getData().keySet().stream().max(Timestamp::compareTo).get(); - break; - } - } - kruizeRecommendationEntry.setInterval_end_time(endInterval); - Map k8sObjectsMap = Map.of(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS, listRecommendationsAPIObject.getKubernetesObjects()); - String k8sObjectString = gson.toJson(k8sObjectsMap); - ObjectMapper objectMapper = new ObjectMapper(); - DateFormat df = new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT); - objectMapper.setDateFormat(df); - try { - kruizeRecommendationEntry.setExtended_data( - objectMapper.readTree( - k8sObjectString - ) - ); - } catch (JsonProcessingException e) { - throw new Exception("Error while creating Extended data due to : " + e.getMessage()); - } - } catch (Exception e) { - kruizeRecommendationEntry = null; - LOGGER.error("Error while converting KruizeObject to KruizeRecommendationEntry due to {}", e.getMessage()); - e.printStackTrace(); - } - return kruizeRecommendationEntry; - } - - public static List convertExperimentEntryToCreateExperimentAPIObject(List entries) throws Exception { - List createExperimentAPIObjects = new ArrayList<>(); - int failureThreshHold = entries.size(); - int failureCount = 0; - for (KruizeExperimentEntry entry : entries) { - try { - JsonNode extended_data = entry.getExtended_data(); - String extended_data_rawJson = extended_data.toString(); - CreateExperimentAPIObject apiObj = new Gson().fromJson(extended_data_rawJson, CreateExperimentAPIObject.class); - apiObj.setExperiment_id(entry.getExperiment_id()); - apiObj.setStatus(entry.getStatus()); - createExperimentAPIObjects.add(apiObj); - } catch (Exception e) { - LOGGER.error("Error in converting to apiObj from db object due to : {}", e.getMessage()); - LOGGER.error(entry.toString()); - failureCount++; - } - } - if (failureThreshHold > 0 && failureCount == failureThreshHold) - throw new Exception("None of the experiments are able to load from DB."); - - return createExperimentAPIObjects; - } - - public static List convertResultEntryToUpdateResultsAPIObject(List kruizeResultsEntries) { - ObjectMapper mapper = new ObjectMapper(); - DateFormat df = new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT); - mapper.setDateFormat(df); - Gson gson = new GsonBuilder() - .disableHtmlEscaping() - .setPrettyPrinting() - .enableComplexMapKeySerialization() - .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) - .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) - .create(); - List updateResultsAPIObjects = new ArrayList<>(); - for (KruizeResultsEntry kruizeResultsEntry : kruizeResultsEntries) { - try { - UpdateResultsAPIObject updateResultsAPIObject = new UpdateResultsAPIObject(); - updateResultsAPIObject.setExperimentName(kruizeResultsEntry.getExperiment_name()); - updateResultsAPIObject.setStartTimestamp(kruizeResultsEntry.getInterval_start_time()); - updateResultsAPIObject.setEndTimestamp(kruizeResultsEntry.getInterval_end_time()); - JsonNode extendedDataNode = kruizeResultsEntry.getExtended_data(); - JsonNode k8sObjectsNode = extendedDataNode.get(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS); - List k8sObjectList = new ArrayList<>(); - if (k8sObjectsNode.isArray()) { - for (JsonNode node : k8sObjectsNode) { - K8sObject k8sObject = gson.fromJson(mapper.writeValueAsString(node), K8sObject.class); - if (null != k8sObject) { - k8sObjectList.add(k8sObject); - } else { - LOGGER.debug("GSON failed to convert the DB Json object in convertResultEntryToUpdateResultsAPIObject"); - } - } - } - List kubernetesAPIObjectList = convertK8sObjectListToKubernetesAPIObjectList(k8sObjectList); - updateResultsAPIObject.setKubernetesObjects(kubernetesAPIObjectList); - updateResultsAPIObjects.add(updateResultsAPIObject); - } catch (Exception e) { - LOGGER.error("Exception occurred while updating local storage: {}", e.getMessage()); - e.printStackTrace(); - } - } - return updateResultsAPIObjects; - } - - private static List convertK8sObjectListToKubernetesAPIObjectList(List k8sObjectList) throws JsonProcessingException { - List kubernetesAPIObjects = new ArrayList<>(); - for (K8sObject k8sObject : k8sObjectList) { - KubernetesAPIObject kubernetesAPIObject = new KubernetesAPIObject( - k8sObject.getName(), - k8sObject.getType(), - k8sObject.getNamespace() - ); - List containerAPIObjects = new ArrayList<>(); - for (Map.Entry entry : k8sObject.getContainerDataMap().entrySet()) { - containerAPIObjects.add(new ContainerAPIObject( - entry.getKey(), - entry.getValue().getContainer_image_name(), - entry.getValue().getContainerRecommendations(), - new ArrayList<>(entry.getValue().getMetrics().values()) - )); - } - kubernetesAPIObject.setContainerAPIObjects(containerAPIObjects); - kubernetesAPIObjects.add(kubernetesAPIObject); - } - return kubernetesAPIObjects; - } - - public static List convertRecommendationEntryToRecommendationAPIObject( - List kruizeRecommendationEntryList) throws InvalidConversionOfRecommendationEntryException { - if (null == kruizeRecommendationEntryList) - return null; - if (kruizeRecommendationEntryList.size() == 0) - return null; - Gson gson = new GsonBuilder() - .disableHtmlEscaping() - .setPrettyPrinting() - .enableComplexMapKeySerialization() - .setDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT) - .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) - .create(); - List listRecommendationsAPIObjectList = new ArrayList<>(); - for (KruizeRecommendationEntry kruizeRecommendationEntry : kruizeRecommendationEntryList) { - // Check if instance of KruizeRecommendationEntry is null - if (null == kruizeRecommendationEntry) { - // Throw an exception stating it cannot be null - throw new InvalidConversionOfRecommendationEntryException( - String.format( - AnalyzerErrorConstants.ConversionErrors.KruizeRecommendationError.NOT_NULL, - KruizeRecommendationEntry.class.getSimpleName() - ) - ); - } - // Create an Object Mapper to extract value from JSON Node - ObjectMapper objectMapper = new ObjectMapper(); - DateFormat df = new SimpleDateFormat(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT); - objectMapper.setDateFormat(df); - // Create a holder for recommendation object to save the result from object mapper - ListRecommendationsAPIObject listRecommendationsAPIObject = null; - JsonNode extendedData = kruizeRecommendationEntry.getExtended_data().get(KruizeConstants.JSONKeys.KUBERNETES_OBJECTS); - if (null == extendedData) - continue; - try { - // If successful, the object mapper returns the list recommendation API Object - List kubernetesAPIObjectList = new ArrayList<>(); - if (extendedData.isArray()) { - for (JsonNode node : extendedData) { - KubernetesAPIObject kubernetesAPIObject = gson.fromJson(objectMapper.writeValueAsString(node), KubernetesAPIObject.class); - if (null != kubernetesAPIObject) { - kubernetesAPIObjectList.add(kubernetesAPIObject); - } else { - LOGGER.debug("GSON failed to convert the DB Json object in convertRecommendationEntryToRecommendationAPIObject"); - } - } - } - if (null != kubernetesAPIObjectList) { - listRecommendationsAPIObject = new ListRecommendationsAPIObject(); - listRecommendationsAPIObject.setKubernetesObjects(kubernetesAPIObjectList); - listRecommendationsAPIObject.setExperimentName(kruizeRecommendationEntry.getExperiment_name()); - listRecommendationsAPIObject.setClusterName(kruizeRecommendationEntry.getCluster_name()); - } - } catch (JsonProcessingException e) { - e.printStackTrace(); - LOGGER.debug(e.getMessage()); - } - if (null != listRecommendationsAPIObject) - listRecommendationsAPIObjectList.add(listRecommendationsAPIObject); - } - if (listRecommendationsAPIObjectList.isEmpty()) - return null; - return listRecommendationsAPIObjectList; - } - - public static KruizePerformanceProfileEntry convertPerfProfileObjToPerfProfileDBObj(PerformanceProfile performanceProfile) { - KruizePerformanceProfileEntry kruizePerformanceProfileEntry = null; - try { - kruizePerformanceProfileEntry = new KruizePerformanceProfileEntry(); - kruizePerformanceProfileEntry.setName(performanceProfile.getName()); - kruizePerformanceProfileEntry.setProfile_version(performanceProfile.getProfile_version()); - kruizePerformanceProfileEntry.setK8s_type(performanceProfile.getK8S_TYPE()); - - ObjectMapper objectMapper = new ObjectMapper(); - try { - kruizePerformanceProfileEntry.setSlo( - objectMapper.readTree(new Gson().toJson(performanceProfile.getSloInfo()))); - } catch (JsonProcessingException e) { - throw new Exception("Error while creating SLO data due to : " + e.getMessage()); - } - } catch (Exception e) { - LOGGER.error("Error occurred while converting Performance Profile Object to PerformanceProfile table due to {}", e.getMessage()); - e.printStackTrace(); - } - return kruizePerformanceProfileEntry; - } - - public static List convertPerformanceProfileEntryToPerformanceProfileObject(List entries) throws Exception { - List performanceProfiles = new ArrayList<>(); - int failureThreshHold = entries.size(); - int failureCount = 0; - for (KruizePerformanceProfileEntry entry : entries) { - try { - JsonNode sloData = entry.getSlo(); - String slo_rawJson = sloData.toString(); - SloInfo sloInfo = new Gson().fromJson(slo_rawJson, SloInfo.class); - PerformanceProfile performanceProfile = new PerformanceProfile( - entry.getName(), entry.getProfile_version(), entry.getK8s_type(), sloInfo); - performanceProfiles.add(performanceProfile); - } catch (Exception e) { - LOGGER.error("Error occurred while reading from Performance Profile DB object due to : {}", e.getMessage()); - LOGGER.error(entry.toString()); - failureCount++; - } - } - if (failureThreshHold > 0 && failureCount == failureThreshHold) - throw new Exception("None of the Performance Profiles loaded from DB."); - - return performanceProfiles; - } - - } - } - - public static class Converters { - private Converters() { - - } - - public static class KruizeObjectConverters { private KruizeObjectConverters() { 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 From c5fb5e24d8b5c3b73b6dd3b025b17f05af0fb485 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 12 Aug 2023 21:55:05 +0530 Subject: [PATCH 60/61] merged Conflicts Signed-off-by: msvinaykumar --- .../verification/validators/TimeDifferenceValidator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 1602ae2ac..12a29f960 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/TimeDifferenceValidator.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/TimeDifferenceValidator.java @@ -40,9 +40,10 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint KruizeObject kruizeObject = ExperimentNameExistValidator.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName()); - Double parsedMeasurementDuration = kruizeObject.getTrial_settings().getMeasurement_durationMinutes_inDouble(); 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); From 0d82ace648b7799c2f527d4ecdd29e3e1232a40a Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Wed, 16 Aug 2023 20:36:33 +0530 Subject: [PATCH 61/61] resolved conflicts Signed-off-by: msvinaykumar --- .../services/UpdateRecommendation.java | 153 ------------------ .../autotune/database/helper/DBConstants.java | 1 - 2 files changed, 154 deletions(-) delete mode 100644 src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java deleted file mode 100644 index 913642917..000000000 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendation.java +++ /dev/null @@ -1,153 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022 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.services; - -import com.autotune.analyzer.exceptions.KruizeResponse; -import com.autotune.analyzer.experiment.ExperimentInitiator; -import com.autotune.analyzer.kruizeObject.KruizeObject; -import com.autotune.analyzer.utils.AnalyzerErrorConstants; -import com.autotune.common.data.result.ExperimentResultData; -import com.autotune.database.service.ExperimentDBService; -import com.autotune.utils.KruizeConstants; -import com.autotune.utils.Utils; -import com.google.gson.Gson; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.sql.Timestamp; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; -import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; - -/** - * - */ -@WebServlet(asyncSupported = true) -public class UpdateRecommendation extends HttpServlet { - private static final long serialVersionUID = 1L; - private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRecommendation.class); - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // 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); - - // Check if experiment_name is provided - if (experiment_name == null || experiment_name.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.EXPERIMENT_NAME_MANDATORY); - return; - } - - // Check if interval_end_time is provided - if (intervalEndTimeStr == null || intervalEndTimeStr.isEmpty()) { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.INTERVAL_END_TIME_MANDATORY); - return; - } - - LOGGER.debug("experiment_name : {} and interval_end_time : {}", experiment_name, intervalEndTimeStr); - // Convert interval_endtime to UTC date format - if (!Utils.DateUtils.isAValidDate(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr)) { - sendErrorResponse( - response, - new Exception(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_EXCPTN), - HttpServletResponse.SC_BAD_REQUEST, - String.format(AnalyzerErrorConstants.APIErrors.ListRecommendationsAPI.INVALID_TIMESTAMP_MSG, intervalEndTimeStr) - ); - return; - } - - //Check if data exist - Timestamp interval_end_time = Utils.DateUtils.getTimeStampFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, intervalEndTimeStr); - ExperimentResultData experimentResultData = null; - try { - experimentResultData = new ExperimentDBService().getExperimentResultData(experiment_name, interval_end_time); - } catch (Exception e) { - sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); - return; - } - - if (null != experimentResultData) { - //Load KruizeObject and generate recommendation - Map mainKruizeExperimentMAP = new HashMap<>(); - try { - //Load KruizeObject - ExperimentDBService experimentDBService = new ExperimentDBService(); - experimentDBService.loadExperimentFromDBByName(mainKruizeExperimentMAP, experiment_name); - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - /* - To restrict the number of rows in the result set, the Load results operation involves locating the appropriate method and configuring the desired limitation. - It's important to note that in order for the Limit rows feature to function correctly, - the CreateExperiment API must adhere strictly to the trail settings' measurement duration and should not allow arbitrary values - */ - int limitRows = (int) ((KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * KruizeConstants.DateFormats.MINUTES_FOR_DAY) / kruizeObject.getTrial_settings().getMeasurement_durationMinutes_inDouble()); - experimentDBService.loadResultsFromDBByName(mainKruizeExperimentMAP, experiment_name, interval_end_time, limitRows); - boolean recommendationCheck = new ExperimentInitiator().generateAndAddRecommendations(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - if (!recommendationCheck) - LOGGER.error("Failed to create recommendation for experiment: %s and interval_end_time: %s", - experimentResultData.getExperiment_name(), - experimentResultData.getIntervalEndTime()); - else { - new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, Collections.singletonList(experimentResultData)); - sendSuccessResponse(response, "Recommendation generated successfully! visit /listRecommendations"); - } - } catch (Exception e) { - e.printStackTrace(); - } - } else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); - return; - } - } - - private void sendSuccessResponse(HttpServletResponse response, String message) throws IOException { - response.setContentType(JSON_CONTENT_TYPE); - response.setCharacterEncoding(CHARACTER_ENCODING); - response.setStatus(HttpServletResponse.SC_CREATED); - PrintWriter out = response.getWriter(); - out.append( - new Gson().toJson( - new KruizeResponse(message, HttpServletResponse.SC_CREATED, "", "SUCCESS") - ) - ); - out.flush(); - } - - public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws - IOException { - if (null != e) { - LOGGER.error(e.toString()); - if (null == errorMsg) errorMsg = e.getMessage(); - } - response.sendError(httpStatusCode, errorMsg); - } -} diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index 251f74b02..a949b21e2 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -16,7 +16,6 @@ public static final class SQLQUERY { 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";