From b83cc30f2edf9068e1b02be167b07e3101241ed5 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 15 Sep 2023 20:46:44 +0530 Subject: [PATCH 01/36] DB partition changes --- Dockerfile.autotune | 1 + .../openshift/kruize-crc-openshift.yaml | 8 +- .../minikube/kruize-crc-minikube.yaml | 2 +- .../openshift/kruize-crc-openshift.yaml | 20 ++- pom.xml | 6 +- src/main/java/com/autotune/Autotune.java | 53 +++++++ .../ExperimentNameExistValidator.java | 7 +- .../KubernetesElementsValidator.java | 2 +- .../PerformanceProfileValidator.java | 4 +- .../validators/TimeDifferenceValidator.java | 5 +- .../services/UpdateRecommendations.java | 29 ++-- .../analyzer/services/UpdateResults.java | 7 + .../analyzer/utils/AnalyzerConstants.java | 3 + .../autotune/database/dao/ExperimentDAO.java | 7 +- .../database/dao/ExperimentDAOImpl.java | 150 +++++++++++++----- .../autotune/database/helper/DBConstants.java | 51 +++++- .../database/service/ExperimentDBService.java | 7 +- .../table/KruizeRecommendationEntry.java | 5 +- .../database/table/KruizeResultsEntry.java | 30 +++- .../com/autotune/jobs/CreatePartition.java | 33 ++++ .../com/autotune/jobs/RetentionPartition.java | 33 ++++ .../com/autotune/utils/KruizeConstants.java | 10 +- 22 files changed, 378 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/autotune/jobs/CreatePartition.java create mode 100644 src/main/java/com/autotune/jobs/RetentionPartition.java diff --git a/Dockerfile.autotune b/Dockerfile.autotune index a928fe326..4eb6020de 100644 --- a/Dockerfile.autotune +++ b/Dockerfile.autotune @@ -39,6 +39,7 @@ RUN mvn -f pom.xml install dependency:copy-dependencies # Now copy the sources and compile and package them COPY src $AUTOTUNE_HOME/src/autotune/src/ RUN mvn -f pom.xml clean package +COPY migrations target/bin/migrations # Create a jlinked JRE specific to the App RUN jlink --strip-debug --compress 2 --no-header-files --no-man-pages --module-path $AUTOTUNE_HOME/java/openjdk/jmods --add-modules java.base,java.compiler,java.desktop,java.logging,java.management,java.naming,java.security.jgss,java.sql,java.xml,jdk.compiler,jdk.httpserver,jdk.unsupported,jdk.crypto.ec --exclude-files=**java_**.properties,**J9TraceFormat**.dat,**OMRTraceFormat**.dat,**j9ddr**.dat,**public_suffix_list**.dat --output jre diff --git a/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml index d70775240..71c6c5965 100644 --- a/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml @@ -35,11 +35,11 @@ data: "hibernate": { "dialect": "org.hibernate.dialect.PostgreSQLDialect", "driver": "org.postgresql.Driver", - "c3p0minsize": 2, - "c3p0maxsize": 5, + "c3p0minsize": 5, + "c3p0maxsize": 10, "c3p0timeout": 300, - "c3p0maxstatements": 50, - "hbm2ddlauto": "update", + "c3p0maxstatements": 100, + "hbm2ddlauto": "none", "showsql": "false", "timezone": "UTC" } diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index f43e7bfad..6e8f13272 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -117,7 +117,7 @@ data: "c3p0maxsize": 5, "c3p0timeout": 300, "c3p0maxstatements": 50, - "hbm2ddlauto": "update", + "hbm2ddlauto": "none", "showsql": "false", "timezone": "UTC" } diff --git a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml index 9dccff25b..1c452216c 100644 --- a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml @@ -94,11 +94,11 @@ data: "hibernate": { "dialect": "org.hibernate.dialect.PostgreSQLDialect", "driver": "org.postgresql.Driver", - "c3p0minsize": 2, - "c3p0maxsize": 5, + "c3p0minsize": 5, + "c3p0maxsize": 10, "c3p0timeout": 300, - "c3p0maxstatements": 50, - "hbm2ddlauto": "update", + "c3p0maxstatements": 100, + "hbm2ddlauto": "none", "showsql": "false", "timezone": "UTC" } @@ -135,6 +135,13 @@ spec: value: kruizeDB - name: PGDATA value: /var/lib/pg_data + resources: + requests: + memory: "10Gi" + cpu: "2" + limits: + memory: "30Gi" + cpu: "2" ports: - containerPort: 5432 volumeMounts: @@ -169,7 +176,7 @@ metadata: app: kruize namespace: openshift-tuning spec: - replicas: 1 + replicas: 10 selector: matchLabels: name: kruize @@ -201,9 +208,10 @@ spec: resources: requests: memory: "4Gi" - cpu: "4" + cpu: "2" limits: memory: "8Gi" + cpu: "2" ports: - name: kruize-port containerPort: 8080 diff --git a/pom.xml b/pom.xml index a5854d4e0..f9266c548 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.autotune autotune - 0.0.18_mvp + 0.0.19_mvp 4.13.0 20201115 @@ -187,10 +187,6 @@ com.autotune.Autotune Autotune - - com.autotune.database.livenessProbe.TestDBConnection - TestDBConnection - diff --git a/src/main/java/com/autotune/Autotune.java b/src/main/java/com/autotune/Autotune.java index d364e0cf5..c4710769d 100644 --- a/src/main/java/com/autotune/Autotune.java +++ b/src/main/java/com/autotune/Autotune.java @@ -20,6 +20,8 @@ import com.autotune.analyzer.exceptions.KruizeErrorHandler; import com.autotune.analyzer.exceptions.MonitoringAgentNotFoundException; import com.autotune.analyzer.exceptions.MonitoringAgentNotSupportedException; +import com.autotune.analyzer.utils.AnalyzerConstants; +import com.autotune.database.helper.DBConstants; import com.autotune.database.init.KruizeHibernateUtil; import com.autotune.experimentManager.core.ExperimentManager; import com.autotune.operator.InitializeDeployment; @@ -38,11 +40,17 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.DispatcherType; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.EnumSet; +import java.util.Scanner; import static com.autotune.utils.ServerContext.*; @@ -83,11 +91,14 @@ public static void main(String[] args) { try { InitializeDeployment.setup_deployment_info(); + // Read and execute the DDLs here + executeDDLs(); } catch (Exception | K8sTypeNotSupportedException | MonitoringAgentNotSupportedException | MonitoringAgentNotFoundException e) { e.printStackTrace(); System.exit(1); } + if (KruizeDeploymentInfo.settings_save_to_db) { Session session = null; try { @@ -145,4 +156,46 @@ private static void startAutotuneNormalMode(ServletContextHandler contextHandler Analyzer.start(contextHandler); ExperimentManager.launch(contextHandler); } + + private static void executeDDLs() throws Exception { + SessionFactory factory = KruizeHibernateUtil.getSessionFactory(); + Session session = null; + try { + session = factory.openSession(); + Path sqlFilePath = Paths.get(AnalyzerConstants.TARGET, AnalyzerConstants.MIGRATIONS, AnalyzerConstants.DDL); + File sqlFile = sqlFilePath.toFile(); + Scanner scanner = new Scanner(sqlFile); + Transaction transaction = session.beginTransaction(); + + while (scanner.hasNextLine()) { + String sqlStatement = scanner.nextLine(); + if (sqlStatement.startsWith("#") || sqlStatement.startsWith("-")) { + continue; + } else { + try { + session.createNativeQuery(sqlStatement).executeUpdate(); + } catch (Exception e) { + if (e.getMessage().contains(DBConstants.DB_MESSAGES.ADD_CONSTRAINT)) { + LOGGER.warn("sql: {} failed due to : {}", sqlStatement, e.getMessage()); + } else { + LOGGER.error("sql: {} failed due to : {}", sqlStatement, e.getMessage()); + } + transaction.commit(); + transaction = session.beginTransaction(); + } + } + } + transaction.commit(); + scanner.close(); + LOGGER.info(DBConstants.DB_MESSAGES.DB_CREATION_SUCCESS); + } catch (Exception e) { + LOGGER.error("Exception occurred while trying to read the DDL file: {}", e.getMessage()); + throw new Exception(e); + } finally { + if (null != session) session.close(); // Close the Hibernate session + } + + LOGGER.info(DBConstants.DB_MESSAGES.DB_LIVELINESS_PROBE_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 index 2e9c64e9a..c09d69def 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 @@ -17,6 +17,7 @@ import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.serviceObjects.verification.annotators.ExperimentNameExist; +import com.autotune.analyzer.services.UpdateResults; import com.autotune.database.service.ExperimentDBService; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; @@ -37,17 +38,17 @@ public class ExperimentNameExistValidator implements ConstraintValidator tempPerformanceProfilesMap = new ConcurrentHashMap<>(); new ExperimentDBService().loadAllPerformanceProfiles(tempPerformanceProfilesMap); UpdateResults.performanceProfilesMap.putAll(tempPerformanceProfilesMap); 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 12a29f960..468f494e0 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 @@ -19,6 +19,7 @@ import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject; import com.autotune.analyzer.serviceObjects.verification.annotators.TimeDifferenceCheck; +import com.autotune.analyzer.services.UpdateResults; import com.autotune.common.data.result.IntervalResults; import com.autotune.utils.KruizeConstants; import jakarta.validation.ConstraintValidator; @@ -38,7 +39,7 @@ public void initialize(TimeDifferenceCheck constraintAnnotation) { public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) { boolean success = false; - KruizeObject kruizeObject = ExperimentNameExistValidator.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName()); + KruizeObject kruizeObject = UpdateResults.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName()); IntervalResults intervalResults = new IntervalResults(updateResultsAPIObject.getStartTimestamp(), updateResultsAPIObject.getEndTimestamp()); Double durationInSeconds = intervalResults.getDuration_in_seconds(); @@ -52,4 +53,4 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint return success; } -} \ No newline at end of file +} diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index ade95bc8d..b6e049b72 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -20,6 +20,7 @@ import com.autotune.analyzer.serviceObjects.ContainerAPIObject; import com.autotune.analyzer.serviceObjects.Converters; import com.autotune.analyzer.serviceObjects.ListRecommendationsAPIObject; +import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.analyzer.utils.GsonUTCDateAdapter; import com.autotune.common.data.ValidationOutputData; @@ -48,6 +49,7 @@ import java.io.IOException; import java.sql.Timestamp; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; @@ -146,25 +148,32 @@ 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 = new ArrayList<>(); ExperimentResultData experimentResultData = null; + Map mainKruizeExperimentMAP = new ConcurrentHashMap<>(); try { - experimentResultDataList = new ExperimentDBService().getExperimentResultData(experiment_name, interval_start_time, interval_end_time); + String clusterName = null; + if (mainKruizeExperimentMAP.containsKey(experiment_name)) { + clusterName = mainKruizeExperimentMAP.get(experiment_name).getClusterName(); + } else { + new ExperimentDBService().loadExperimentFromDBByName(mainKruizeExperimentMAP, experiment_name); + request.getServletContext().setAttribute(AnalyzerConstants.EXPERIMENT_MAP, mainKruizeExperimentMAP); + if (null != mainKruizeExperimentMAP.get(experiment_name)) { + clusterName = mainKruizeExperimentMAP.get(experiment_name).getClusterName(); + } + } + if (null != clusterName) + experimentResultDataList = new ExperimentDBService().getExperimentResultData(experiment_name, clusterName, interval_start_time, interval_end_time); // Todo this object is not required } catch (Exception e) { sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); return; } if (experimentResultDataList.size() > 0) { - - //Load KruizeObject and generate recommendation - Map mainKruizeExperimentMAP = new HashMap<>(); + //generate recommendation try { - //Load KruizeObject - ExperimentDBService experimentDBService = new ExperimentDBService(); - experimentDBService.loadExperimentFromDBByName(mainKruizeExperimentMAP, experiment_name); KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); - new ExperimentInitiator().generateAndAddRecommendations(kruizeObject, experimentResultDataList, interval_start_time, interval_end_time); + new ExperimentInitiator().generateAndAddRecommendations(kruizeObject, experimentResultDataList, interval_start_time, interval_end_time); // TODO: experimentResultDataList not required ValidationOutputData validationOutputData = new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, experimentResultDataList); if (validationOutputData.isSuccess()) { sendSuccessResponse(response, kruizeObject, interval_end_time); @@ -202,7 +211,7 @@ private void sendSuccessResponse(HttpServletResponse response, KruizeObject ko, response.setContentType(JSON_CONTENT_TYPE); response.setCharacterEncoding(CHARACTER_ENCODING); response.setStatus(HttpServletResponse.SC_CREATED); - List recommendationList = new ArrayList<>(); + List recommendationList = new ArrayList<>(); //TODO: Executing two identical SQL SELECT queries against the database instead of just one is causing a performance issue. set 'showSQL' flag is set to true to debug. try { LOGGER.debug(ko.getKubernetes_objects().toString()); ListRecommendationsAPIObject listRecommendationsAPIObject = Converters.KruizeObjectConverters. diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 670235cba..bc2e0847d 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -59,10 +59,14 @@ public class UpdateResults extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger LOGGER = LoggerFactory.getLogger(UpdateResults.class); public static ConcurrentHashMap performanceProfilesMap = new ConcurrentHashMap<>(); + public static ConcurrentHashMap mainKruizeExperimentMAP; @Override public void init(ServletConfig config) throws ServletException { super.init(config); + mainKruizeExperimentMAP = (ConcurrentHashMap) config.getServletContext().getAttribute(AnalyzerConstants.EXPERIMENT_MAP); + if (mainKruizeExperimentMAP == null) + mainKruizeExperimentMAP = new ConcurrentHashMap<>(); } @Override @@ -71,6 +75,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) Timer.Sample timerUpdateResults = Timer.start(MetricsConfig.meterRegistry()); Map mKruizeExperimentMap = new ConcurrentHashMap(); try { + int initialSize = mainKruizeExperimentMAP.size(); performanceProfilesMap = (ConcurrentHashMap) getServletContext() .getAttribute(AnalyzerConstants.PerformanceProfileConstants.PERF_PROFILE_MAP); String inputData = request.getReader().lines().collect(Collectors.joining()); @@ -85,6 +90,8 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) ExperimentInitiator experimentInitiator = new ExperimentInitiator(); experimentInitiator.validateAndAddExperimentResults(updateResultsAPIObjects); List failureAPIObjs = experimentInitiator.getFailedUpdateResultsAPIObjects(); + if (initialSize != mainKruizeExperimentMAP.size()) + request.getServletContext().setAttribute(AnalyzerConstants.EXPERIMENT_MAP, mainKruizeExperimentMAP); List jsonObjectList = new ArrayList<>(); if (failureAPIObjs.size() > 0) { failureAPIObjs.forEach( diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerConstants.java index 1e4fc4417..dcd2157db 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerConstants.java @@ -89,6 +89,9 @@ public class AnalyzerConstants { public static final String PERSISTANCE_STORAGE = "persistance_storage"; public static final String RESULTS_COUNT = "results_count"; public static final int GC_THRESHOLD_COUNT = 100; + public static final String TARGET = "target/bin"; + public static final String MIGRATIONS = "migrations"; + public static final String DDL = "kruize_experiments_ddl.sql"; private AnalyzerConstants() { diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 558ea6710..9c60d84ce 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -50,7 +50,7 @@ public interface ExperimentDAO { // Load all results for a particular experimentName - List loadResultsByExperimentName(String experimentName, Timestamp interval_start_time, Integer limitRows) throws Exception; + List loadResultsByExperimentName(String experimentName, String cluster_name, Timestamp interval_start_time, Integer limitRows) throws Exception; // Load all recommendations of a particular experiment List loadRecommendationsByExperimentName(String experimentName) throws Exception; @@ -61,10 +61,11 @@ public interface ExperimentDAO { // Load all recommendations of a particular experiment and interval end Time - KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, Timestamp interval_end_time) throws Exception; + KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, String cluster_name, Timestamp interval_end_time) throws Exception; // Get KruizeResult Record - List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; + List getKruizeResultsEntry(String experiment_name, String cluster_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception; + public void addPartitions(String tableName, String month, String year, int dayOfTheMonth, String partitionType) 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 de8783360..369b2030b 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -18,15 +18,18 @@ 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; import java.sql.Timestamp; -import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; +import java.util.stream.IntStream; import static com.autotune.database.helper.DBConstants.SQLQUERY.*; @@ -40,20 +43,22 @@ public ValidationOutputData addExperimentToDB(KruizeExperimentEntry kruizeExperi Transaction tx = null; String statusValue = "failure"; Timer.Sample timerAddExpDB = Timer.start(MetricsConfig.meterRegistry()); - try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { - try { - tx = session.beginTransaction(); - session.persist(kruizeExperimentEntry); - tx.commit(); - validationOutputData.setSuccess(true); - statusValue = "success"; - } catch (HibernateException e) { - LOGGER.error("Not able to save experiment due to {}", e.getMessage()); - if (tx != null) tx.rollback(); - e.printStackTrace(); - validationOutputData.setSuccess(false); - validationOutputData.setMessage(e.getMessage()); - //todo save error to API_ERROR_LOG + try { + try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { + try { + tx = session.beginTransaction(); + session.persist(kruizeExperimentEntry); + tx.commit(); + validationOutputData.setSuccess(true); + statusValue = "success"; + } catch (HibernateException e) { + LOGGER.error("Not able to save experiment due to {}", e.getMessage()); + if (tx != null) tx.rollback(); + e.printStackTrace(); + validationOutputData.setSuccess(false); + validationOutputData.setMessage(e.getMessage()); + //TODO: save error to API_ERROR_LOG + } } } catch (Exception e) { LOGGER.error("Not able to save experiment due to {}", e.getMessage()); @@ -67,6 +72,44 @@ public ValidationOutputData addExperimentToDB(KruizeExperimentEntry kruizeExperi return validationOutputData; } + @Override + public void addPartitions(String tableName, String month, String year, int dayOfTheMonth, String partitionType) { + Transaction tx; + try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { + tx = session.beginTransaction(); + // Create a YearMonth object and get the current month and current year + YearMonth yearMonth = YearMonth.of(Integer.parseInt(year), Integer.parseInt(month)); + + // check the partition type and create corresponding query + if (partitionType.equalsIgnoreCase(DBConstants.PARTITION_TYPES.BY_MONTH)) { + // Get the last day of the month + int lastDayOfMonth = yearMonth.lengthOfMonth(); + IntStream.range(dayOfTheMonth, lastDayOfMonth + 1).forEach(i -> { + String daterange = String.format(DB_PARTITION_DATERANGE, tableName, year, month, String.format("%02d", i), tableName, + year, month, String.format("%02d", i), year, month, String.format("%02d", i)); + session.createNativeQuery(daterange).executeUpdate(); + }); + } else if (partitionType.equalsIgnoreCase(DBConstants.PARTITION_TYPES.BY_15_DAYS)) { + IntStream.range(1, 16).forEach(i -> { + String daterange = String.format(DB_PARTITION_DATERANGE, tableName, year, month, String.format("%02d", i), tableName, + year, month, String.format("%02d", i), year, month, String.format("%02d", i)); + session.createNativeQuery(daterange).executeUpdate(); + }); + } else if (partitionType.equalsIgnoreCase(DBConstants.PARTITION_TYPES.BY_DAY)) { + String daterange = String.format(DB_PARTITION_DATERANGE, tableName, year, month, String.format("%02d", 1), tableName, + year, month, String.format("%02d", 1), year, month, String.format("%02d", 1)); + session.createNativeQuery(daterange).executeUpdate(); + } else { + LOGGER.error(DBConstants.DB_MESSAGES.INVALID_PARTITION_TYPE); + throw new Exception(DBConstants.DB_MESSAGES.INVALID_PARTITION_TYPE); + } + + tx.commit(); + } catch (Exception e) { + LOGGER.error("Exception occurred while adding the partition: {}", e.getMessage()); + } + } + @Override public ValidationOutputData addResultsToDB(KruizeResultsEntry resultsEntry) { ValidationOutputData validationOutputData = new ValidationOutputData(false, null, null); @@ -84,7 +127,8 @@ public ValidationOutputData addResultsToDB(KruizeResultsEntry resultsEntry) { if (ex.getCause() instanceof org.hibernate.exception.ConstraintViolationException) { validationOutputData.setSuccess(false); 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()) + String.format(DBConstants.DB_MESSAGES.RECORD_ALREADY_EXISTS, resultsEntry.getExperiment_name(), + resultsEntry.getInterval_start_time(), resultsEntry.getInterval_end_time()) ); } else { throw new Exception(ex.getMessage()); @@ -119,28 +163,55 @@ public List addToDBAndFetchFailedResults(List elementsInSuccessOnly = kruizeResultsEntries.stream() - .filter(entry -> !failedResultsEntries.contains(entry)) - .collect(Collectors.toList()); - tx = session.beginTransaction(); - for (KruizeResultsEntry entry : elementsInSuccessOnly) { - session.merge(entry); - } - tx.commit(); - } + statusValue = "success"; } catch (Exception e) { LOGGER.error("Not able to save experiment due to {}", e.getMessage()); @@ -165,7 +236,7 @@ public ValidationOutputData addRecommendationToDB(KruizeRecommendationEntry reco Timer.Sample timerAddRecDB = Timer.start(MetricsConfig.meterRegistry()); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { try { - KruizeRecommendationEntry existingRecommendationEntry = loadRecommendationsByExperimentNameAndDate(recommendationEntry.getExperiment_name(), recommendationEntry.getInterval_end_time()); + KruizeRecommendationEntry existingRecommendationEntry = loadRecommendationsByExperimentNameAndDate(recommendationEntry.getExperiment_name(), recommendationEntry.getCluster_name(), recommendationEntry.getInterval_end_time()); if (null == existingRecommendationEntry) { tx = session.beginTransaction(); session.persist(recommendationEntry); @@ -397,14 +468,15 @@ public List loadExperimentByName(String experimentName) t } @Override - public List loadResultsByExperimentName(String experimentName, Timestamp interval_end_time, Integer limitRows) throws Exception { + public List loadResultsByExperimentName(String experimentName, String cluster_name, Timestamp interval_end_time, Integer limitRows) throws Exception { // TODO: load only experimentStatus=inProgress , playback may not require completed experiments List kruizeResultsEntries = null; String statusValue = "failure"; Timer.Sample timerLoadResultsExpName = Timer.start(MetricsConfig.meterRegistry()); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { if (null != limitRows && null != interval_end_time) { - kruizeResultsEntries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE, KruizeResultsEntry.class) + kruizeResultsEntries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT, KruizeResultsEntry.class) + .setParameter(KruizeConstants.JSONKeys.CLUSTER_NAME, cluster_name) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName) .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) .setMaxResults(limitRows) @@ -449,12 +521,13 @@ public List loadRecommendationsByExperimentName(Strin } @Override - public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, Timestamp interval_end_time) throws Exception { + public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, String cluster_name, Timestamp interval_end_time) throws Exception { KruizeRecommendationEntry recommendationEntries = null; String statusValue = "failure"; Timer.Sample timerLoadRecExpNameDate = Timer.start(MetricsConfig.meterRegistry()); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { recommendationEntries = session.createQuery(SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME_AND_END_TIME, KruizeRecommendationEntry.class) + .setParameter(KruizeConstants.JSONKeys.CLUSTER_NAME, cluster_name) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName) .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) .getSingleResult(); @@ -496,28 +569,31 @@ public List loadPerformanceProfileByName(String p @Override - public List getKruizeResultsEntry(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { + public List getKruizeResultsEntry(String experiment_name, String cluster_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.CLUSTER_NAME, cluster_name) .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.CLUSTER_NAME, cluster_name) .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.CLUSTER_NAME, cluster_name) .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); + LOGGER.error(DBConstants.DB_MESSAGES.DATA_NOT_FOUND_KRUIZE_RESULTS, experiment_name, interval_end_time); kruizeResultsEntryList = null; } catch (Exception e) { kruizeResultsEntryList = null; diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index a949b21e2..ba5341808 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -9,17 +9,56 @@ public static final class SQLQUERY { public static final String SELECT_FROM_EXPERIMENTS_BY_EXP_NAME = "from KruizeExperimentEntry k WHERE k.experiment_name = :experimentName"; public static final String SELECT_FROM_RESULTS = "from KruizeResultsEntry"; public static final String SELECT_FROM_RESULTS_BY_EXP_NAME = "from KruizeResultsEntry k WHERE k.experiment_name = :experimentName"; - public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_end_time <= :%s ORDER BY k.interval_end_time DESC", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME, KruizeConstants.JSONKeys.INTERVAL_START_TIME); - public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_START_END_TIME = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_start_time >= :%s and k.interval_end_time <= :%s", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_START_TIME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); - public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_end_time = :%s", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); - public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_MAX_END_TIME = String.format("from KruizeResultsEntry k WHERE k.experiment_name = :%s and k.interval_end_time = (SELECT MAX(e.interval_end_time) FROM KruizeResultsEntry e where e.experiment_name = :%s )", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME); - public static final String SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME = "from KruizeRecommendationEntry k WHERE k.experiment_name = :experimentName"; - public static final String SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME_AND_END_TIME = String.format("from KruizeRecommendationEntry k WHERE k.experiment_name = :%s and k.interval_end_time= :%s", KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); + public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_AND_LIMIT = String.format("from KruizeResultsEntry k " + + "WHERE k.cluster_name = :%s and k.experiment_name = :%s and" + + " k.interval_end_time <= :%s ORDER BY k.interval_end_time DESC", + KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); + public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT = String.format("from KruizeResultsEntry k " + + "WHERE k.cluster_name = :%s and k.experiment_name = :%s and k.interval_end_time <= :%s " + + "ORDER BY k.interval_end_time DESC", + KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); + public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_START_END_TIME = String.format("from KruizeResultsEntry k " + + "WHERE k.cluster_name = :%s and k.experiment_name = :%s and k.interval_start_time >= :%s and " + + "k.interval_end_time <= :%s", + KruizeConstants.JSONKeys.CLUSTER_NAME, 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.cluster_name = :%s and k.experiment_name = :%s and k.interval_end_time = :%s", KruizeConstants.JSONKeys.CLUSTER_NAME, 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.cluster_name = :%s and 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.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME); + public static final String SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME = String.format("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.cluster_name= :%s and k.experiment_name = :%s and k.interval_end_time= :%s", KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); public static final String SELECT_FROM_RECOMMENDATIONS = "from KruizeRecommendationEntry"; 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"; public static final String DELETE_FROM_RESULTS_BY_EXP_NAME = "DELETE FROM KruizeResultsEntry k WHERE k.experiment_name = :experimentName"; public static final String DELETE_FROM_RECOMMENDATIONS_BY_EXP_NAME = "DELETE FROM KruizeRecommendationEntry k WHERE k.experiment_name = :experimentName"; + public static final String DB_PARTITION_DATERANGE = "CREATE TABLE IF NOT EXISTS %s_%s%s%s PARTITION OF %s FOR VALUES FROM ('%s-%s-%s 00:00:00.000') TO ('%s-%s-%s 23:59:59');"; } + + public static final class TABLE_NAMES { + public static final String KRUIZE_EXPERIMENTS = "kruize_experiments"; + public static final String KRUIZE_RESULTS = "kruize_results"; + public static final String KRUIZE_RECOMMENDATIONS = "kruize_recommendations"; + public static final String KRUIZE_PERFORMANCE_PROFILES = "kruize_performance_profiles"; + + } + + public static final class PARTITION_TYPES { + public static final String BY_MONTH = "by_month"; + public static final String BY_15_DAYS = "by_fifteen_days"; + public static final String BY_DAY = "by_day"; + } + public static final class DB_MESSAGES { + public static final String RECORD_ALREADY_EXISTS = "A record with the name %s already exists within the timestamp range starting from %s and ending on %s."; + public static final String DUPLICATE_KEY = "duplicate key value"; + public static final String NO_PARTITION_RELATION = "no partition of relation"; + public static final String CREATE_PARTITION_RETRY = "Create partition and retry !"; + public static final String INVALID_PARTITION_TYPE = "Invalid Partition Type"; + public static final String DATA_NOT_FOUND_KRUIZE_RESULTS = "Data not found in kruizeResultsEntry for exp_name : {} interval_end_time : {} "; + public static final String ADD_CONSTRAINT = "add constraint"; + public static final String DB_CREATION_SUCCESS = "DB creation successful !"; + public static final String DB_LIVELINESS_PROBE_SUCCESS = "DB Liveliness probe connection successful!"; + + } + + } diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 904699544..7f790e9de 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -144,8 +144,9 @@ public void loadAllPerformanceProfiles(Map performan public void loadResultsFromDBByName(Map mainKruizeExperimentMap, String experimentName, Timestamp interval_end_time, Integer limitRows) throws Exception { ExperimentInterface experimentInterface = new ExperimentInterfaceImpl(); + KruizeObject kruizeObject = mainKruizeExperimentMap.get(experimentName); // Load results from the DB and save to local - List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, interval_end_time, limitRows); + List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, kruizeObject.getClusterName(), interval_end_time, limitRows); if (null != kruizeResultsEntries && !kruizeResultsEntries.isEmpty()) { List updateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(kruizeResultsEntries); if (null != updateResultsAPIObjects && !updateResultsAPIObjects.isEmpty()) { @@ -341,9 +342,9 @@ public boolean updateExperimentStatus(KruizeObject kruizeObject, AnalyzerConstan } - public List getExperimentResultData(String experiment_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { + public List getExperimentResultData(String experiment_name, String clusterName, 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); + List kruizeResultsEntryList = experimentDAO.getKruizeResultsEntry(experiment_name, clusterName, interval_start_time, interval_end_time); if (null != kruizeResultsEntryList) { List updateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(kruizeResultsEntryList); for (UpdateResultsAPIObject updateObject : updateResultsAPIObjects) { diff --git a/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java b/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java index 53310d83e..845bd30c1 100644 --- a/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java +++ b/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java @@ -23,11 +23,10 @@ unique = false) }) public class KruizeRecommendationEntry { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long recommendation_id; private String version; + @Id private String experiment_name; + @Id private Timestamp interval_end_time; private String cluster_name; @JdbcTypeCode(SqlTypes.JSON) diff --git a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java index 4fd5c0a60..3c99d61fb 100644 --- a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java +++ b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java @@ -29,18 +29,24 @@ */ @Entity @Table(name = "kruize_results", - uniqueConstraints = {@UniqueConstraint(columnNames = {"experiment_name", "interval_start_time", "interval_end_time"})}, - indexes = @Index( - name = "idx_result_experiment_name", - columnList = "experiment_name", - unique = false)) + indexes = { + @Index( + name = "idx_result_experiment_name", + columnList = "experiment_name"), + @Index( + name = "idx_result_cluster_name", + columnList = "experiment_name"), + @Index( + name = "idx_result_interval_end_time", + columnList = "interval_end_time") + }) public class KruizeResultsEntry { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long interval_id; private String version; + @Id private String experiment_name; + private String cluster_name; private Timestamp interval_start_time; + @Id private Timestamp interval_end_time; private double duration_minutes; @JdbcTypeCode(SqlTypes.JSON) @@ -114,4 +120,12 @@ public List getErrorReasons() { public void setErrorReasons(List errorReasons) { this.errorReasons = errorReasons; } + + public String getCluster_name() { + return cluster_name; + } + + public void setCluster_name(String cluster_name) { + this.cluster_name = cluster_name; + } } diff --git a/src/main/java/com/autotune/jobs/CreatePartition.java b/src/main/java/com/autotune/jobs/CreatePartition.java new file mode 100644 index 000000000..72d0d1154 --- /dev/null +++ b/src/main/java/com/autotune/jobs/CreatePartition.java @@ -0,0 +1,33 @@ +package com.autotune.jobs; + +import com.autotune.analyzer.exceptions.K8sTypeNotSupportedException; +import com.autotune.analyzer.exceptions.MonitoringAgentNotFoundException; +import com.autotune.analyzer.exceptions.MonitoringAgentNotSupportedException; +import com.autotune.database.init.KruizeHibernateUtil; +import com.autotune.operator.InitializeDeployment; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class CreatePartition { + private static final Logger LOGGER = LoggerFactory.getLogger(CreatePartition.class); + + public static void main(String[] args) { + LOGGER.info("Checking Liveliness probe DB connection..."); + try { + InitializeDeployment.setup_deployment_info(); + } catch (Exception | K8sTypeNotSupportedException | MonitoringAgentNotSupportedException | + MonitoringAgentNotFoundException e) { + e.printStackTrace(); + System.exit(1); + } + SessionFactory factory = KruizeHibernateUtil.getSessionFactory(); + + Session session = factory.openSession(); + + session.close(); + LOGGER.info("DB Liveliness probe connection successful!"); + } +} diff --git a/src/main/java/com/autotune/jobs/RetentionPartition.java b/src/main/java/com/autotune/jobs/RetentionPartition.java new file mode 100644 index 000000000..9edaa110f --- /dev/null +++ b/src/main/java/com/autotune/jobs/RetentionPartition.java @@ -0,0 +1,33 @@ +package com.autotune.jobs; + +import com.autotune.analyzer.exceptions.K8sTypeNotSupportedException; +import com.autotune.analyzer.exceptions.MonitoringAgentNotFoundException; +import com.autotune.analyzer.exceptions.MonitoringAgentNotSupportedException; +import com.autotune.database.init.KruizeHibernateUtil; +import com.autotune.operator.InitializeDeployment; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class RetentionPartition { + private static final Logger LOGGER = LoggerFactory.getLogger(RetentionPartition.class); + + public static void main(String[] args) { + LOGGER.info("Checking Liveliness probe DB connection..."); + try { + InitializeDeployment.setup_deployment_info(); + } catch (Exception | K8sTypeNotSupportedException | MonitoringAgentNotSupportedException | + MonitoringAgentNotFoundException e) { + e.printStackTrace(); + System.exit(1); + } + SessionFactory factory = KruizeHibernateUtil.getSessionFactory(); + + Session session = factory.openSession(); + + session.close(); + LOGGER.info("DB Liveliness probe connection successful!"); + } +} diff --git a/src/main/java/com/autotune/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java index dbd6c7920..8e4012cf2 100644 --- a/src/main/java/com/autotune/utils/KruizeConstants.java +++ b/src/main/java/com/autotune/utils/KruizeConstants.java @@ -189,6 +189,7 @@ public static final class JSONKeys { public static final String INTERVAL_START_TIME = "interval_start_time"; public static final String INTERVAL_END_TIME = "interval_end_time"; public static final String DURATION_IN_MINUTES = "duration_in_minutes"; + public static final String DURATION_IN_HOURS = "duration_in_hours"; public static final String MONITORING_START_TIME = "monitoring_start_time"; public static final String MONITORING_END_TIME = "monitoring_end_time"; public static final String PODS_COUNT = "pods_count"; @@ -201,6 +202,11 @@ public static final class JSONKeys { public static final String NOTIFICATIONS = "notifications"; public static final String DURATION_BASED = "duration_based"; public static final String PROFILE_BASED = "profile_based"; + public static final String COST = "cost"; + public static final String PERFORMANCE = "performance"; + public static final String RECOMMENDATION_TERMS = "recommendation_terms"; + public static final String RECOMMENDATION_ENGINES = "recommendation_engines"; + public static final String CONFIDENCE_LEVEL = "confidence_level"; private JSONKeys() { } @@ -248,6 +254,8 @@ public static class TimeConv { 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 NO_OF_HOURS_IN_7_DAYS = 168; + public static int NO_OF_HOURS_15_DAYS = 360; private TimeConv() { } @@ -443,7 +451,7 @@ private DurationAmount() { public static final class RecommendationDurationRanges { private static final double BUFFER_VALUE_IN_MINS = (TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS / TimeConv.NO_OF_SECONDS_PER_MINUTE); /* SHORT TERM */ - public static final double SHORT_TERM_TOTAL_DURATION_UPPER_BOUND_MINS = + public static final double SHORT_TERM_TOTAL_DURATION_UPPER_BOUND_MINS = (DurationAmount.SHORT_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) + BUFFER_VALUE_IN_MINS; public static final double SHORT_TERM_TOTAL_DURATION_LOWER_BOUND_MINS = (DurationAmount.SHORT_TERM_DURATION_DAYS * TimeConv.NO_OF_HOURS_PER_DAY * TimeConv.NO_OF_MINUTES_PER_HOUR) - BUFFER_VALUE_IN_MINS; From 087c0e9952e75bfbe3d100564069c1b885a745de Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sat, 16 Sep 2023 21:16:02 +0530 Subject: [PATCH 02/36] added migration folder Signed-off-by: msvinaykumar --- migrations/kruize_experiments_ddl.sql | 11 +++++++++++ .../java/com/autotune/database/helper/DBHelpers.java | 2 ++ 2 files changed, 13 insertions(+) create mode 100644 migrations/kruize_experiments_ddl.sql diff --git a/migrations/kruize_experiments_ddl.sql b/migrations/kruize_experiments_ddl.sql new file mode 100644 index 000000000..0d94195a3 --- /dev/null +++ b/migrations/kruize_experiments_ddl.sql @@ -0,0 +1,11 @@ +create table IF NOT EXISTS kruize_experiments (experiment_id varchar(255) not null, cluster_name varchar(255), datasource jsonb, experiment_name varchar(255), extended_data jsonb, meta_data jsonb, mode varchar(255), performance_profile varchar(255), status varchar(255), target_cluster varchar(255), version varchar(255), primary key (experiment_id)); +create table IF NOT EXISTS kruize_performance_profiles (name varchar(255) not null, k8s_type varchar(255), profile_version float(53) not null, slo jsonb, primary key (name)); +create table IF NOT EXISTS kruize_recommendations (interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) not null, extended_data jsonb, version varchar(255), primary key (cluster_name, experiment_name, interval_end_time)) PARTITION BY RANGE (interval_end_time); +create table IF NOT EXISTS kruize_results (interval_start_time timestamp(6) not null, interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) not null, duration_minutes float(53) not null, extended_data jsonb, meta_data jsonb, version varchar(255), primary key (cluster_name, experiment_name, interval_end_time, interval_start_time)) PARTITION BY RANGE (interval_end_time); +alter table if exists kruize_experiments add constraint UK_experiment_name unique (experiment_name); +create index IF NOT EXISTS idx_recommendation_experiment_name on kruize_recommendations (experiment_name); +create index IF NOT EXISTS idx_recommendation_cluster_name on kruize_recommendations (cluster_name); +create index IF NOT EXISTS idx_recommendation_interval_end_time on kruize_recommendations (interval_end_time); +create index IF NOT EXISTS idx_result_experiment_name on kruize_results (experiment_name); +create index IF NOT EXISTS idx_result_cluster_name on kruize_results (cluster_name); +create index IF NOT EXISTS idx_result_interval_end_time on kruize_results (interval_end_time); diff --git a/src/main/java/com/autotune/database/helper/DBHelpers.java b/src/main/java/com/autotune/database/helper/DBHelpers.java index 7519a5858..4ff5e369b 100644 --- a/src/main/java/com/autotune/database/helper/DBHelpers.java +++ b/src/main/java/com/autotune/database/helper/DBHelpers.java @@ -23,6 +23,7 @@ import com.autotune.analyzer.recommendations.ContainerRecommendations; import com.autotune.analyzer.recommendations.Recommendation; import com.autotune.analyzer.serviceObjects.*; +import com.autotune.analyzer.services.UpdateResults; import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.analyzer.utils.GsonUTCDateAdapter; @@ -303,6 +304,7 @@ public static KruizeResultsEntry convertExperimentResultToExperimentResultsTable kruizeResultsEntry = new KruizeResultsEntry(); kruizeResultsEntry.setVersion(experimentResultData.getVersion()); kruizeResultsEntry.setExperiment_name(experimentResultData.getExperiment_name()); + kruizeResultsEntry.setCluster_name(UpdateResults.mainKruizeExperimentMAP.get(experimentResultData.getExperiment_name()).getClusterName()); kruizeResultsEntry.setInterval_start_time(experimentResultData.getIntervalStartTime()); kruizeResultsEntry.setInterval_end_time(experimentResultData.getIntervalEndTime()); kruizeResultsEntry.setDuration_minutes( From e1dc9fdf1095a24d3467850bd23b9a0f1c73b824 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Sun, 17 Sep 2023 20:40:25 +0530 Subject: [PATCH 03/36] incorporated review comment Signed-off-by: msvinaykumar --- migrations/kruize_experiments_ddl.sql | 6 ++---- .../analyzer/services/UpdateRecommendations.java | 1 - .../com/autotune/analyzer/services/UpdateResults.java | 10 +--------- .../database/table/KruizeRecommendationEntry.java | 4 ---- .../autotune/database/table/KruizeResultsEntry.java | 3 --- 5 files changed, 3 insertions(+), 21 deletions(-) diff --git a/migrations/kruize_experiments_ddl.sql b/migrations/kruize_experiments_ddl.sql index 0d94195a3..8d9002b71 100644 --- a/migrations/kruize_experiments_ddl.sql +++ b/migrations/kruize_experiments_ddl.sql @@ -1,11 +1,9 @@ create table IF NOT EXISTS kruize_experiments (experiment_id varchar(255) not null, cluster_name varchar(255), datasource jsonb, experiment_name varchar(255), extended_data jsonb, meta_data jsonb, mode varchar(255), performance_profile varchar(255), status varchar(255), target_cluster varchar(255), version varchar(255), primary key (experiment_id)); create table IF NOT EXISTS kruize_performance_profiles (name varchar(255) not null, k8s_type varchar(255), profile_version float(53) not null, slo jsonb, primary key (name)); -create table IF NOT EXISTS kruize_recommendations (interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) not null, extended_data jsonb, version varchar(255), primary key (cluster_name, experiment_name, interval_end_time)) PARTITION BY RANGE (interval_end_time); -create table IF NOT EXISTS kruize_results (interval_start_time timestamp(6) not null, interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) not null, duration_minutes float(53) not null, extended_data jsonb, meta_data jsonb, version varchar(255), primary key (cluster_name, experiment_name, interval_end_time, interval_start_time)) PARTITION BY RANGE (interval_end_time); +create table IF NOT EXISTS kruize_recommendations (interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255), extended_data jsonb, version varchar(255), primary key (experiment_name, interval_end_time)) PARTITION BY RANGE (interval_end_time); +create table IF NOT EXISTS kruize_results (interval_start_time timestamp(6) not null, interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) , duration_minutes float(53) not null, extended_data jsonb, meta_data jsonb, version varchar(255), primary key (experiment_name, interval_end_time, interval_start_time)) PARTITION BY RANGE (interval_end_time); alter table if exists kruize_experiments add constraint UK_experiment_name unique (experiment_name); create index IF NOT EXISTS idx_recommendation_experiment_name on kruize_recommendations (experiment_name); -create index IF NOT EXISTS idx_recommendation_cluster_name on kruize_recommendations (cluster_name); create index IF NOT EXISTS idx_recommendation_interval_end_time on kruize_recommendations (interval_end_time); create index IF NOT EXISTS idx_result_experiment_name on kruize_results (experiment_name); -create index IF NOT EXISTS idx_result_cluster_name on kruize_results (cluster_name); create index IF NOT EXISTS idx_result_interval_end_time on kruize_results (interval_end_time); diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index b6e049b72..5e1217597 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -157,7 +157,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) clusterName = mainKruizeExperimentMAP.get(experiment_name).getClusterName(); } else { new ExperimentDBService().loadExperimentFromDBByName(mainKruizeExperimentMAP, experiment_name); - request.getServletContext().setAttribute(AnalyzerConstants.EXPERIMENT_MAP, mainKruizeExperimentMAP); if (null != mainKruizeExperimentMAP.get(experiment_name)) { clusterName = mainKruizeExperimentMAP.get(experiment_name).getClusterName(); } diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index bc2e0847d..062f7f231 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -64,20 +64,14 @@ public class UpdateResults extends HttpServlet { @Override public void init(ServletConfig config) throws ServletException { super.init(config); - mainKruizeExperimentMAP = (ConcurrentHashMap) config.getServletContext().getAttribute(AnalyzerConstants.EXPERIMENT_MAP); - if (mainKruizeExperimentMAP == null) - mainKruizeExperimentMAP = new ConcurrentHashMap<>(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String statusValue = "failure"; Timer.Sample timerUpdateResults = Timer.start(MetricsConfig.meterRegistry()); - Map mKruizeExperimentMap = new ConcurrentHashMap(); + mainKruizeExperimentMAP = new ConcurrentHashMap(); try { - int initialSize = mainKruizeExperimentMAP.size(); - 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)); @@ -90,8 +84,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) ExperimentInitiator experimentInitiator = new ExperimentInitiator(); experimentInitiator.validateAndAddExperimentResults(updateResultsAPIObjects); List failureAPIObjs = experimentInitiator.getFailedUpdateResultsAPIObjects(); - if (initialSize != mainKruizeExperimentMAP.size()) - request.getServletContext().setAttribute(AnalyzerConstants.EXPERIMENT_MAP, mainKruizeExperimentMAP); List jsonObjectList = new ArrayList<>(); if (failureAPIObjs.size() > 0) { failureAPIObjs.forEach( diff --git a/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java b/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java index 845bd30c1..9dfd076b1 100644 --- a/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java +++ b/src/main/java/com/autotune/database/table/KruizeRecommendationEntry.java @@ -13,10 +13,6 @@ name = "idx_recommendation_experiment_name", columnList = "experiment_name", unique = false), - @Index( - name = "idx_recommendation_cluster_name", - columnList = "cluster_name", - unique = false), @Index( name = "idx_recommendation_interval_end_time", columnList = "interval_end_time", diff --git a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java index 3c99d61fb..4e2082d1f 100644 --- a/src/main/java/com/autotune/database/table/KruizeResultsEntry.java +++ b/src/main/java/com/autotune/database/table/KruizeResultsEntry.java @@ -33,9 +33,6 @@ @Index( name = "idx_result_experiment_name", columnList = "experiment_name"), - @Index( - name = "idx_result_cluster_name", - columnList = "experiment_name"), @Index( name = "idx_result_interval_end_time", columnList = "interval_end_time") From 7993bdd48b62b732430551ace1aaeca542ebf3c6 Mon Sep 17 00:00:00 2001 From: Dinakar Guniguntala Date: Mon, 18 Sep 2023 19:34:51 +0530 Subject: [PATCH 04/36] Bump remote_monitoring to 0.0.19_rm Signed-off-by: Dinakar Guniguntala --- .../crc/BYODB-installation/minikube/kruize-crc-minikube.yaml | 2 +- .../crc/BYODB-installation/openshift/kruize-crc-openshift.yaml | 2 +- .../minikube/kruize-crc-minikube.yaml | 2 +- .../openshift/kruize-crc-openshift.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml index 9c88285a3..d57c20b38 100644 --- a/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml @@ -65,7 +65,7 @@ spec: spec: containers: - name: kruize - image: kruize/autotune_operator:0.0.18_rm + image: kruize/autotune_operator:0.0.19_rm imagePullPolicy: Always volumeMounts: - name: config-volume diff --git a/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml index 71c6c5965..5d5b8f64a 100644 --- a/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml @@ -65,7 +65,7 @@ spec: spec: containers: - name: kruize - image: kruize/autotune_operator:0.0.18_rm + image: kruize/autotune_operator:0.0.19_rm imagePullPolicy: Always volumeMounts: - name: config-volume diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index 6e8f13272..feb2c31e2 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -143,7 +143,7 @@ spec: spec: containers: - name: kruize - image: kruize/autotune_operator:0.0.18_rm + image: kruize/autotune_operator:0.0.19_rm imagePullPolicy: Always volumeMounts: - name: config-volume diff --git a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml index 1c452216c..b5fb365c4 100644 --- a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml @@ -189,7 +189,7 @@ spec: serviceAccountName: kruize-sa containers: - name: kruize - image: kruize/autotune_operator:0.0.18_rm + image: kruize/autotune_operator:0.0.19_rm imagePullPolicy: Always volumeMounts: - name: config-volume From 2720e9f5dbed3d75c7217b2ec60ccefd9300950f Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 18 Sep 2023 19:59:11 +0530 Subject: [PATCH 05/36] supress Number of pods cannot be zero message Signed-off-by: msvinaykumar --- .../engine/DurationBasedRecommendationEngine.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java b/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java index 1602c74ac..9e79a32cc 100644 --- a/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java +++ b/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java @@ -516,12 +516,12 @@ private boolean populateRecommendation(String recommendationTerm, if (numPods == 0) { RecommendationNotification recommendationNotification = new RecommendationNotification(RecommendationConstants.RecommendationNotification.ERROR_NUM_PODS_CANNOT_BE_ZERO); notifications.add(recommendationNotification); - LOGGER.error("Number of pods cannot be zero"); + LOGGER.debug("Number of pods cannot be zero"); isSuccess = false; } else if (numPods < 0) { RecommendationNotification recommendationNotification = new RecommendationNotification(RecommendationConstants.RecommendationNotification.ERROR_NUM_PODS_CANNOT_BE_NEGATIVE); notifications.add(recommendationNotification); - LOGGER.error("Number of pods cannot be negative"); + LOGGER.debug("Number of pods cannot be negative"); isSuccess = false; } else { recommendation.setPodsCount(numPods); From 590fab8df14abd6a3e3440969cbc2a04302091bd Mon Sep 17 00:00:00 2001 From: bharathappali Date: Mon, 18 Sep 2023 20:00:07 +0530 Subject: [PATCH 06/36] Adds threshold for limit rows Signed-off-by: bharathappali --- .../ResourceOptimizationOpenshiftImpl.java | 14 ++++++++++---- .../recommendations/utils/RecommendationUtils.java | 11 +++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java 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 f06d92e91..a4a2fb3e0 100644 --- a/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java +++ b/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java @@ -23,6 +23,7 @@ import com.autotune.analyzer.recommendations.RecommendationNotification; import com.autotune.analyzer.recommendations.engine.DurationBasedRecommendationEngine; import com.autotune.analyzer.recommendations.engine.KruizeRecommendationEngine; +import com.autotune.analyzer.recommendations.utils.RecommendationUtils; import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.common.data.result.ContainerData; import com.autotune.common.data.result.ExperimentResultData; @@ -87,26 +88,31 @@ public void generateRecommendation(KruizeObject kruizeObject, List mainKruizeExperimentMap = new HashMap<>(); mainKruizeExperimentMap.put(experiment_name, kruizeObject); new ExperimentDBService().loadResultsFromDBByName(mainKruizeExperimentMap, experiment_name, interval_end_time, - limitRows); + practicalLimitRows); //TODO: Will be updated once algo is completed for (ExperimentResultData experimentResultData : experimentResultDataList) { if (null != kruizeObject && null != experimentResultData) { diff --git a/src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java b/src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java new file mode 100644 index 000000000..349cdb0ba --- /dev/null +++ b/src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java @@ -0,0 +1,11 @@ +package com.autotune.analyzer.recommendations.utils; + +public class RecommendationUtils { + public static int getThreshold(int value, int failoverPercentage, boolean direction) { + if (direction) { + return Math.round(value + value * (failoverPercentage / 100.0f)); + } else { + return Math.round(value - value * (failoverPercentage / 100.0f)); + } + } +} \ No newline at end of file From 387eeb4ab82bd4480754d8b00ca2c9d7d34db1d6 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Mon, 18 Sep 2023 20:01:46 +0530 Subject: [PATCH 07/36] supress Number of pods cannot be zero Signed-off-by: msvinaykumar --- .../engine/DurationBasedRecommendationEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java b/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java index 9e79a32cc..9a21fe98b 100644 --- a/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java +++ b/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java @@ -516,7 +516,7 @@ private boolean populateRecommendation(String recommendationTerm, if (numPods == 0) { RecommendationNotification recommendationNotification = new RecommendationNotification(RecommendationConstants.RecommendationNotification.ERROR_NUM_PODS_CANNOT_BE_ZERO); notifications.add(recommendationNotification); - LOGGER.debug("Number of pods cannot be zero"); + LOGGER.debug("Number of pods cannot be zero"); // isSuccess = false; } else if (numPods < 0) { RecommendationNotification recommendationNotification = new RecommendationNotification(RecommendationConstants.RecommendationNotification.ERROR_NUM_PODS_CANNOT_BE_NEGATIVE); From 2bd5cdbb62ef87ae13a36db25900800da5471f08 Mon Sep 17 00:00:00 2001 From: Chandrakala Subramanyam Date: Mon, 28 Aug 2023 15:39:13 +0530 Subject: [PATCH 08/36] Changed the experiment name and ignored kruize-ui while fetching pod name Signed-off-by: Chandrakala Subramanyam --- tests/scripts/common/common_functions.sh | 2 +- .../remote_monitoring_tests/helpers/generate_rm_jsons.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/scripts/common/common_functions.sh b/tests/scripts/common/common_functions.sh index 1e0707697..952d93950 100755 --- a/tests/scripts/common/common_functions.sh +++ b/tests/scripts/common/common_functions.sh @@ -1760,7 +1760,7 @@ function get_autotune_pod_log() { echo "target = $target" if [ ${target} == "crc" ]; then - autotune_pod=$(kubectl get pod -n ${NAMESPACE} | grep kruize | cut -d " " -f1) + autotune_pod=$(kubectl get pod -n ${NAMESPACE} | grep kruize | grep -v kruize-ui | cut -d " " -f1) pod_log_msg=$(kubectl logs ${autotune_pod} -n ${NAMESPACE}) else autotune_pod=$(kubectl get pod -n ${NAMESPACE} | grep autotune | cut -d " " -f1) diff --git a/tests/scripts/remote_monitoring_tests/helpers/generate_rm_jsons.py b/tests/scripts/remote_monitoring_tests/helpers/generate_rm_jsons.py index 9ae9848dd..1286d3b40 100644 --- a/tests/scripts/remote_monitoring_tests/helpers/generate_rm_jsons.py +++ b/tests/scripts/remote_monitoring_tests/helpers/generate_rm_jsons.py @@ -9,7 +9,7 @@ total_exps = 10 -exp_name = "quarkus-resteasy-kruize-min-http-response-time-db" +exp_name = "quarkus-exp" kubernetes_object_name = "tfb-qrh-deployment" kubernetes_object_namespace = "default" container_image_name = "kruize/tfb-qrh:1.13.2.F_et17" From 4969e9eb60ec69d6eb06fd9dfbe55b6e9a9f2302 Mon Sep 17 00:00:00 2001 From: Chandrakala Subramanyam Date: Tue, 12 Sep 2023 09:34:37 +0530 Subject: [PATCH 09/36] Updated stress test to bulk upload results and invoke update recommendation Signed-off-by: Chandrakala Subramanyam --- .../jmx/kruize_remote_monitoring_stress.jmx | 554 +++++++++--------- ...ize_remote_monitoring_stress_openshift.jmx | 552 +++++++++-------- .../stress_test/json/input.json | 110 ++++ .../remote_monitoring_stress_test.sh | 6 +- 4 files changed, 660 insertions(+), 562 deletions(-) create mode 100644 tests/scripts/remote_monitoring_tests/stress_test/json/input.json diff --git a/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress.jmx b/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress.jmx index 1f1630040..ab7765575 100644 --- a/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress.jmx +++ b/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress.jmx @@ -15,12 +15,12 @@ port - ${__P(port,32565)} + ${__P(port,31915)} = users - ${__P(users,10000)} + ${__P(users,100)} = @@ -40,7 +40,7 @@ num_res - ${__P(num_res,100)} + ${__P(num_res,30)} = @@ -191,123 +191,66 @@ true - + + true + + + +def threadNum = ${__threadNum} + +// Read JSON from file +def inputFile = new File("./json/input.json") +def jsonSlurper = new groovy.json.JsonSlurper() +def dataTemplate = jsonSlurper.parseText(inputFile.text) +def exp = dataTemplate[0].experiment_name + +def jsonArray = [] + + +def currentTime = Calendar.getInstance() +def startTime = currentTime.clone() +def endTime = currentTime.clone() +endTime.add(Calendar.MINUTE, 15) + +// Use SimpleDateFormat to format the date-time +def dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + +if (dataTemplate && dataTemplate.size() > 0) { +for (int i = 1; i <= 100; i++) { + + def data = dataTemplate[0]?.clone() + + data.experiment_name = "quarkus-resteasy-kruize-min-http-response-time-db-" + threadNum + data.kubernetes_objects[0].name = "tfb-qrh-deployment-" + threadNum + data.kubernetes_objects[0].namespace = "default-" + threadNum + + data.interval_start_time = dateFormat.format(startTime.time) + data.interval_end_time = dateFormat.format(endTime.time) + + startTime = endTime.clone() + endTime.add(Calendar.MINUTE, 15) + + jsonArray.add(data) + + if (i == 100) + props.put("e_time_" + threadNum, data.interval_end_time) +} +} + +def requestBody = new groovy.json.JsonBuilder(jsonArray).toPrettyString() + +vars.put("requestBody", requestBody) + + groovy + + + true false - [ - { - "version": "1.0", - "experiment_name": "quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum}", - "interval_start_time": "${start_time}", - "interval_end_time": "${end_time}", - "kubernetes_objects": [ - { - "type": "deployment", - "name": "tfb-qrh-deployment-${__threadNum}", - "namespace": "default-${__threadNum}", - "containers": [ - { - "container_image_name": "kruize/tfb-qrh:1.13.2.F_et17", - "container_name": "tfb-server-1", - "metrics": [ - { - "name": "cpuRequest", - "results": { - "aggregation_info": { - "sum": 4.4, - "avg": 1.1, - "format": "cores" - } - } - }, - { - "name": "cpuLimit", - "results": { - "aggregation_info": { - "sum": 2.0, - "avg": 0.5, - "format": "cores" - } - } - }, - { - "name": "cpuUsage", - "results": { - "aggregation_info": { - "min": 0.14, - "max": 0.84, - "sum": 0.84, - "avg": 0.12, - "format": "cores" - } - } - }, - { - "name": "cpuThrottle", - "results": { - "aggregation_info": { - "sum": 0.19, - "max": 0.09, - "avg": 0.045, - "format": "cores" - } - } - }, - { - "name": "memoryRequest", - "results": { - "aggregation_info": { - "sum": 250.85, - "avg": 50.21, - "format": "MiB" - } - } - }, - { - "name": "memoryLimit", - "results": { - "aggregation_info": { - "sum": 500, - "avg": 100, - "format": "MiB" - } - } - }, - { - "name": "memoryUsage", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 198.50, - "sum": 198.50, - "avg": 40.1, - "format": "MiB" - } - } - }, - { - "name": "memoryRSS", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 123.6, - "sum": 123.6, - "avg": 31.91, - "format": "MiB" - } - } - } - ] - } - ] - } - ] - } -] - + ${requestBody} = @@ -375,10 +318,88 @@ - - 200 - - + + + + + false + quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum} + = + true + experiment_name + + + false + ${__P(e_time_${__threadNum})} + = + true + interval_end_time + + + + + + + + /updateRecommendations + POST + true + false + true + false + + + + + + + + 201 + + + Assertion.response_code + false + 8 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + continue @@ -470,7 +491,7 @@ - 200 + 10 @@ -483,7 +504,7 @@ - + true @@ -497,7 +518,7 @@ FileUtils.writeStringToFile(new File(logdir + "/reco_jsons/reco" + Str - + continue false @@ -511,138 +532,68 @@ FileUtils.writeStringToFile(new File(logdir + "/reco_jsons/reco" + Str true - + true - import org.apache.commons.io.FileUtils; -import java.io.File; + +def threadNum = ${__threadNum} -String loop = vars.get("repeat"); -String logdir = vars.get("logdir"); -int threadNum = ctx.getThreadNum(); -FileUtils.writeStringToFile(new File(logdir + "/reco_jsons_" + loop + "/reco" + String.valueOf(threadNum) + ".json"), vars.get("myResponse")); +// Read JSON from file +def inputFile = new File("./json/input.json") +def jsonSlurper = new groovy.json.JsonSlurper() +def dataTemplate = jsonSlurper.parseText(inputFile.text) +def exp = dataTemplate[0].experiment_name + +def jsonArray = [] + +def currentTime = Calendar.getInstance() +def startTime = currentTime.clone() +def endTime = currentTime.clone() + +def minutesToAdd = 1500 + +startTime.add(Calendar.MINUTE, minutesToAdd) +endTime.add(Calendar.MINUTE, minutesToAdd + 15) + +// Use SimpleDateFormat to format the date-time +def dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + +for (int i = 1; i <= 100; i++) { + + def data = dataTemplate[0].clone() + + data.experiment_name = "quarkus-resteasy-kruize-min-http-response-time-db-" + threadNum + data.kubernetes_objects[0].name = "tfb-qrh-deployment-" + threadNum + data.kubernetes_objects[0].namespace = "default-" + threadNum + + data.interval_start_time = dateFormat.format(startTime.time) + data.interval_end_time = dateFormat.format(endTime.time) + + startTime = endTime.clone() + endTime.add(Calendar.MINUTE, 15) + + jsonArray.add(data) + + if (i == 100) + props.put("e_time_" + threadNum, data.interval_end_time) + +} + +def requestBody = new groovy.json.JsonBuilder(jsonArray).toPrettyString() + +vars.put("requestBody", requestBody) - java + groovy - + true false - [ - { - "version": "1.0", - "experiment_name": "quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum}", - "interval_start_time": "${start_time}", - "interval_end_time": "${end_time}", - "kubernetes_objects": [ - { - "type": "deployment", - "name": "tfb-qrh-deployment-${__threadNum}", - "namespace": "default-${__threadNum}", - "containers": [ - { - "container_image_name": "kruize/tfb-qrh:1.13.2.F_et17", - "container_name": "tfb-server-1", - "metrics": [ - { - "name": "cpuRequest", - "results": { - "aggregation_info": { - "sum": 4.4, - "avg": 1.1, - "format": "cores" - } - } - }, - { - "name": "cpuLimit", - "results": { - "aggregation_info": { - "sum": 2.0, - "avg": 0.5, - "format": "cores" - } - } - }, - { - "name": "cpuUsage", - "results": { - "aggregation_info": { - "min": 0.14, - "max": 0.84, - "sum": 0.84, - "avg": 0.12, - "format": "cores" - } - } - }, - { - "name": "cpuThrottle", - "results": { - "aggregation_info": { - "sum": 0.19, - "max": 0.09, - "avg": 0.045, - "format": "cores" - } - } - }, - { - "name": "memoryRequest", - "results": { - "aggregation_info": { - "sum": 250.85, - "avg": 50.21, - "format": "MiB" - } - } - }, - { - "name": "memoryLimit", - "results": { - "aggregation_info": { - "sum": 500, - "avg": 100, - "format": "MiB" - } - } - }, - { - "name": "memoryUsage", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 198.50, - "sum": 198.50, - "avg": 40.1, - "format": "MiB" - } - } - }, - { - "name": "memoryRSS", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 123.6, - "sum": 123.6, - "avg": 31.91, - "format": "MiB" - } - } - } - ] - } - ] - } - ] - } -] - + ${requestBody} = @@ -709,40 +660,87 @@ FileUtils.writeStringToFile(new File(logdir + "/reco_jsons_" + loop + - - true + + + + + + false + quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum} + = + true + experiment_name + + + false + ${__P(e_time_${__threadNum})} + = + true + interval_end_time + + + + + + + + /updateRecommendations + POST + true + false + true + false + + + + + + + + 201 + + + Assertion.response_code + false + 8 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + - - import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.time.Instant; -import java.time.format.DateTimeFormatter; - -String timeString = vars.get("start_time"); - -Instant instant = Instant.parse(timeString); - -LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); -LocalDateTime startDateTime = dateTime.plusMinutes(15); -DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); -String startTimeString = startDateTime.format(formatter); - -vars.put("start_time", startTimeString); - -// Add 15 minutes to the newTime object - -Instant instant = Instant.parse(startTimeString); - -dateTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); -LocalDateTime endDateTime = dateTime.plusMinutes(15); -String endTimeString = endDateTime.format(formatter); - - -// Store the new time in a JMeter variable -vars.put("end_time", endTimeString); - - java - + @@ -772,10 +770,6 @@ vars.put("end_time", endTimeString); - - 1000 - - 200 @@ -1003,7 +997,7 @@ vars.put("start_time", startTimeString); ${host} - ${port} + ${port} diff --git a/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress_openshift.jmx b/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress_openshift.jmx index 5a4d74d22..d9e3aab9b 100644 --- a/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress_openshift.jmx +++ b/tests/scripts/remote_monitoring_tests/stress_test/jmx/kruize_remote_monitoring_stress_openshift.jmx @@ -15,12 +15,12 @@ port - ${__P(port,32565)} + ${__P(port,31915)} = users - ${__P(users,10000)} + ${__P(users,100)} = @@ -40,7 +40,7 @@ num_res - ${__P(num_res,100)} + ${__P(num_res,30)} = @@ -191,123 +191,66 @@ true - + + true + + + +def threadNum = ${__threadNum} + +// Read JSON from file +def inputFile = new File("./json/input.json") +def jsonSlurper = new groovy.json.JsonSlurper() +def dataTemplate = jsonSlurper.parseText(inputFile.text) +def exp = dataTemplate[0].experiment_name + +def jsonArray = [] + + +def currentTime = Calendar.getInstance() +def startTime = currentTime.clone() +def endTime = currentTime.clone() +endTime.add(Calendar.MINUTE, 15) + +// Use SimpleDateFormat to format the date-time +def dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + +if (dataTemplate && dataTemplate.size() > 0) { +for (int i = 1; i <= 100; i++) { + + def data = dataTemplate[0]?.clone() + + data.experiment_name = "quarkus-resteasy-kruize-min-http-response-time-db-" + threadNum + data.kubernetes_objects[0].name = "tfb-qrh-deployment-" + threadNum + data.kubernetes_objects[0].namespace = "default-" + threadNum + + data.interval_start_time = dateFormat.format(startTime.time) + data.interval_end_time = dateFormat.format(endTime.time) + + startTime = endTime.clone() + endTime.add(Calendar.MINUTE, 15) + + jsonArray.add(data) + + if (i == 100) + props.put("e_time_" + threadNum, data.interval_end_time) +} +} + +def requestBody = new groovy.json.JsonBuilder(jsonArray).toPrettyString() + +vars.put("requestBody", requestBody) + + groovy + + + true false - [ - { - "version": "1.0", - "experiment_name": "quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum}", - "interval_start_time": "${start_time}", - "interval_end_time": "${end_time}", - "kubernetes_objects": [ - { - "type": "deployment", - "name": "tfb-qrh-deployment-${__threadNum}", - "namespace": "default-${__threadNum}", - "containers": [ - { - "container_image_name": "kruize/tfb-qrh:1.13.2.F_et17", - "container_name": "tfb-server-1", - "metrics": [ - { - "name": "cpuRequest", - "results": { - "aggregation_info": { - "sum": 4.4, - "avg": 1.1, - "format": "cores" - } - } - }, - { - "name": "cpuLimit", - "results": { - "aggregation_info": { - "sum": 2.0, - "avg": 0.5, - "format": "cores" - } - } - }, - { - "name": "cpuUsage", - "results": { - "aggregation_info": { - "min": 0.14, - "max": 0.84, - "sum": 0.84, - "avg": 0.12, - "format": "cores" - } - } - }, - { - "name": "cpuThrottle", - "results": { - "aggregation_info": { - "sum": 0.19, - "max": 0.09, - "avg": 0.045, - "format": "cores" - } - } - }, - { - "name": "memoryRequest", - "results": { - "aggregation_info": { - "sum": 250.85, - "avg": 50.21, - "format": "MiB" - } - } - }, - { - "name": "memoryLimit", - "results": { - "aggregation_info": { - "sum": 500, - "avg": 100, - "format": "MiB" - } - } - }, - { - "name": "memoryUsage", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 198.50, - "sum": 198.50, - "avg": 40.1, - "format": "MiB" - } - } - }, - { - "name": "memoryRSS", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 123.6, - "sum": 123.6, - "avg": 31.91, - "format": "MiB" - } - } - } - ] - } - ] - } - ] - } -] - + ${requestBody} = @@ -375,10 +318,88 @@ - - 200 - - + + + + + false + quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum} + = + true + experiment_name + + + false + ${__P(e_time_${__threadNum})} + = + true + interval_end_time + + + + + + + + /updateRecommendations + POST + true + false + true + false + + + + + + + + 201 + + + Assertion.response_code + false + 8 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + continue @@ -470,7 +491,7 @@ - 200 + 10 @@ -483,7 +504,7 @@ - + true @@ -497,7 +518,7 @@ FileUtils.writeStringToFile(new File(logdir + "/reco_jsons/reco" + Str - + continue false @@ -511,138 +532,68 @@ FileUtils.writeStringToFile(new File(logdir + "/reco_jsons/reco" + Str true - + true - import org.apache.commons.io.FileUtils; -import java.io.File; + +def threadNum = ${__threadNum} -String loop = vars.get("repeat"); -String logdir = vars.get("logdir"); -int threadNum = ctx.getThreadNum(); -FileUtils.writeStringToFile(new File(logdir + "/reco_jsons_" + loop + "/reco" + String.valueOf(threadNum) + ".json"), vars.get("myResponse")); +// Read JSON from file +def inputFile = new File("./json/input.json") +def jsonSlurper = new groovy.json.JsonSlurper() +def dataTemplate = jsonSlurper.parseText(inputFile.text) +def exp = dataTemplate[0].experiment_name + +def jsonArray = [] + +def currentTime = Calendar.getInstance() +def startTime = currentTime.clone() +def endTime = currentTime.clone() + +def minutesToAdd = 1500 + +startTime.add(Calendar.MINUTE, minutesToAdd) +endTime.add(Calendar.MINUTE, minutesToAdd + 15) + +// Use SimpleDateFormat to format the date-time +def dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + +for (int i = 1; i <= 100; i++) { + + def data = dataTemplate[0].clone() + + data.experiment_name = "quarkus-resteasy-kruize-min-http-response-time-db-" + threadNum + data.kubernetes_objects[0].name = "tfb-qrh-deployment-" + threadNum + data.kubernetes_objects[0].namespace = "default-" + threadNum + + data.interval_start_time = dateFormat.format(startTime.time) + data.interval_end_time = dateFormat.format(endTime.time) + + startTime = endTime.clone() + endTime.add(Calendar.MINUTE, 15) + + jsonArray.add(data) + + if (i == 100) + props.put("e_time_" + threadNum, data.interval_end_time) + +} + +def requestBody = new groovy.json.JsonBuilder(jsonArray).toPrettyString() + +vars.put("requestBody", requestBody) - java + groovy - + true false - [ - { - "version": "1.0", - "experiment_name": "quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum}", - "interval_start_time": "${start_time}", - "interval_end_time": "${end_time}", - "kubernetes_objects": [ - { - "type": "deployment", - "name": "tfb-qrh-deployment-${__threadNum}", - "namespace": "default-${__threadNum}", - "containers": [ - { - "container_image_name": "kruize/tfb-qrh:1.13.2.F_et17", - "container_name": "tfb-server-1", - "metrics": [ - { - "name": "cpuRequest", - "results": { - "aggregation_info": { - "sum": 4.4, - "avg": 1.1, - "format": "cores" - } - } - }, - { - "name": "cpuLimit", - "results": { - "aggregation_info": { - "sum": 2.0, - "avg": 0.5, - "format": "cores" - } - } - }, - { - "name": "cpuUsage", - "results": { - "aggregation_info": { - "min": 0.14, - "max": 0.84, - "sum": 0.84, - "avg": 0.12, - "format": "cores" - } - } - }, - { - "name": "cpuThrottle", - "results": { - "aggregation_info": { - "sum": 0.19, - "max": 0.09, - "avg": 0.045, - "format": "cores" - } - } - }, - { - "name": "memoryRequest", - "results": { - "aggregation_info": { - "sum": 250.85, - "avg": 50.21, - "format": "MiB" - } - } - }, - { - "name": "memoryLimit", - "results": { - "aggregation_info": { - "sum": 500, - "avg": 100, - "format": "MiB" - } - } - }, - { - "name": "memoryUsage", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 198.50, - "sum": 198.50, - "avg": 40.1, - "format": "MiB" - } - } - }, - { - "name": "memoryRSS", - "results": { - "aggregation_info": { - "min": 50.6, - "max": 123.6, - "sum": 123.6, - "avg": 31.91, - "format": "MiB" - } - } - } - ] - } - ] - } - ] - } -] - + ${requestBody} = @@ -709,40 +660,87 @@ FileUtils.writeStringToFile(new File(logdir + "/reco_jsons_" + loop + - - true + + + + + + false + quarkus-resteasy-kruize-min-http-response-time-db-${__threadNum} + = + true + experiment_name + + + false + ${__P(e_time_${__threadNum})} + = + true + interval_end_time + + + + + + + + /updateRecommendations + POST + true + false + true + false + + + + + + + + 201 + + + Assertion.response_code + false + 8 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + - - import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.time.Instant; -import java.time.format.DateTimeFormatter; - -String timeString = vars.get("start_time"); - -Instant instant = Instant.parse(timeString); - -LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); -LocalDateTime startDateTime = dateTime.plusMinutes(15); -DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); -String startTimeString = startDateTime.format(formatter); - -vars.put("start_time", startTimeString); - -// Add 15 minutes to the newTime object - -Instant instant = Instant.parse(startTimeString); - -dateTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); -LocalDateTime endDateTime = dateTime.plusMinutes(15); -String endTimeString = endDateTime.format(formatter); - - -// Store the new time in a JMeter variable -vars.put("end_time", endTimeString); - - java - + @@ -772,10 +770,6 @@ vars.put("end_time", endTimeString); - - 1000 - - 200 diff --git a/tests/scripts/remote_monitoring_tests/stress_test/json/input.json b/tests/scripts/remote_monitoring_tests/stress_test/json/input.json new file mode 100644 index 000000000..96b213306 --- /dev/null +++ b/tests/scripts/remote_monitoring_tests/stress_test/json/input.json @@ -0,0 +1,110 @@ +[ + { + "version": "1.0", + "experiment_name": "quarkus-resteasy-kruize-min-http-response-time-db", + "interval_start_time": "", + "interval_end_time": "", + "kubernetes_objects": [ + { + "type": "deployment", + "name": "tfb-qrh-deployment", + "namespace": "default", + "containers": [ + { + "container_image_name": "kruize/tfb-qrh:1.13.2.F_et17", + "container_name": "tfb-server-1", + "metrics": [ + { + "name": "cpuRequest", + "results": { + "aggregation_info": { + "sum": 4.4, + "avg": 1.1, + "format": "cores" + } + } + }, + { + "name": "cpuLimit", + "results": { + "aggregation_info": { + "sum": 2.0, + "avg": 0.5, + "format": "cores" + } + } + }, + { + "name": "cpuUsage", + "results": { + "aggregation_info": { + "min": 0.14, + "max": 0.84, + "sum": 0.84, + "avg": 0.12, + "format": "cores" + } + } + }, + { + "name": "cpuThrottle", + "results": { + "aggregation_info": { + "sum": 0.19, + "max": 0.09, + "avg": 0.045, + "format": "cores" + } + } + }, + { + "name": "memoryRequest", + "results": { + "aggregation_info": { + "sum": 250.85, + "avg": 50.21, + "format": "MiB" + } + } + }, + { + "name": "memoryLimit", + "results": { + "aggregation_info": { + "sum": 500, + "avg": 100, + "format": "MiB" + } + } + }, + { + "name": "memoryUsage", + "results": { + "aggregation_info": { + "min": 50.6, + "max": 198.50, + "sum": 198.50, + "avg": 40.1, + "format": "MiB" + } + } + }, + { + "name": "memoryRSS", + "results": { + "aggregation_info": { + "min": 50.6, + "max": 123.6, + "sum": 123.6, + "avg": 31.91, + "format": "MiB" + } + } + } + ] + } + ] + } + ] + } +] diff --git a/tests/scripts/remote_monitoring_tests/stress_test/remote_monitoring_stress_test.sh b/tests/scripts/remote_monitoring_tests/stress_test/remote_monitoring_stress_test.sh index 299753374..33144a2af 100755 --- a/tests/scripts/remote_monitoring_tests/stress_test/remote_monitoring_stress_test.sh +++ b/tests/scripts/remote_monitoring_tests/stress_test/remote_monitoring_stress_test.sh @@ -33,9 +33,9 @@ CLUSTER_TYPE=minikube DEPLOYMENT_NAME=kruize CONTAINER_NAME=kruize NAMESPACE=monitoring -users=1000 +users=100 rampup=200 -num_res=100 +num_res=30 loop=1 RESOURCE_OPTIMIZATION_JSON="../json_files/resource_optimization_openshift.json" @@ -58,7 +58,7 @@ function get_kruize_pod_log() { echo "" echo "Fetch the kruize pod logs and store in ${log}..." - kruize_pod=$(kubectl get pod -n ${NAMESPACE} | grep kruize | cut -d " " -f1) + kruize_pod=$(kubectl get pod -n ${NAMESPACE} | grep kruize | grep -v kruize-ui | cut -d " " -f1) kubectl logs -f ${kruize_pod} -n ${NAMESPACE} > ${log} 2>&1 & } From cf2be0cdcd004620840e669b2a905f50f1c22d2f Mon Sep 17 00:00:00 2001 From: Chandrakala Subramanyam Date: Fri, 15 Sep 2023 10:32:20 +0530 Subject: [PATCH 10/36] Included pytest html version for consistent html format Signed-off-by: Chandrakala Subramanyam --- tests/scripts/remote_monitoring_tests/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/remote_monitoring_tests/requirements.txt b/tests/scripts/remote_monitoring_tests/requirements.txt index 589b3685a..1b6deedb9 100644 --- a/tests/scripts/remote_monitoring_tests/requirements.txt +++ b/tests/scripts/remote_monitoring_tests/requirements.txt @@ -1,4 +1,4 @@ pytest requests jinja2 -pytest-html +pytest-html==3.2.0 From 1a07ff34728376804236640e85997431818a2b08 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Wed, 20 Sep 2023 20:26:40 +0530 Subject: [PATCH 11/36] fixed scale warning issue and removed global map and static reference. Signed-off-by: msvinaykumar --- .../experiment/ExperimentInitiator.java | 43 ++-- .../analyzer/serviceObjects/BaseSO.java | 5 - .../analyzer/serviceObjects/Converters.java | 190 +++++++++--------- .../UpdateResultsAPIObject.java | 15 +- .../annotators/ExperimentNameExist.java | 38 ---- .../validators/CompareDateValidator.java | 12 +- .../ExperimentNameExistValidator.java | 62 ------ .../KubernetesElementsValidator.java | 5 +- .../PerformanceProfileValidator.java | 15 +- .../validators/TimeDifferenceValidator.java | 32 +-- .../services/UpdateRecommendations.java | 33 +-- .../analyzer/services/UpdateResults.java | 5 - .../utils/AnalyzerErrorConstants.java | 2 +- .../data/result/ExperimentResultData.java | 10 + .../database/dao/ExperimentDAOImpl.java | 26 ++- .../autotune/database/helper/DBConstants.java | 2 + .../autotune/database/helper/DBHelpers.java | 4 +- .../database/service/ExperimentDBService.java | 15 +- 18 files changed, 238 insertions(+), 276 deletions(-) delete mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/ExperimentNameExist.java delete mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java index a1c4b7ad4..acaa44adc 100644 --- a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java +++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java @@ -38,6 +38,7 @@ import java.lang.reflect.Field; import java.sql.Timestamp; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Initiates new experiment data validations and push into queue for worker to @@ -76,7 +77,7 @@ public static List getErrorMap(List errorMessages) { } ); responses = new ArrayList<>(); - groupSimilarMap.forEach((httpCode,errorText) -> + groupSimilarMap.forEach((httpCode, errorText) -> { responses.add( new KruizeResponse(errorText, httpCode, "", "ERROR", null) @@ -140,21 +141,37 @@ public void validateAndAddExperimentResults(List updateR .failFast(false) .buildValidatorFactory() .getValidator(); - + Map mainKruizeExperimentMAP = new ConcurrentHashMap(); 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()); + String experimentName = object.getExperimentName(); + if (!mainKruizeExperimentMAP.containsKey(experimentName)) { + try { + new ExperimentDBService().loadExperimentFromDBByName(mainKruizeExperimentMAP, experimentName); // TODO try to avoid DB + } catch (Exception e) { + LOGGER.error(e.getMessage()); + } + } + if (mainKruizeExperimentMAP.containsKey(experimentName)) { + object.setKruizeObject(mainKruizeExperimentMAP.get(object.getExperimentName())); + 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.setErrors(getErrorMap(errorReasons)); + failedUpdateResultsAPIObjects.add(object); } + } else { + List errorReasons = new ArrayList<>(); + errorReasons.add(String.format("Not Found : experiment_name doesn't exist - %s", experimentName)); object.setErrors(getErrorMap(errorReasons)); failedUpdateResultsAPIObjects.add(object); } diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/BaseSO.java b/src/main/java/com/autotune/analyzer/serviceObjects/BaseSO.java index bdea150e6..ce33262a0 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/BaseSO.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/BaseSO.java @@ -15,7 +15,6 @@ *******************************************************************************/ 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; @@ -25,7 +24,6 @@ public abstract class BaseSO { @SerializedName("version") private String apiVersion; @NotBlank(groups = InitialValidation.class) - @ExperimentNameExist(groups = ExperimentNameExistValidation.class) @SerializedName("experiment_name") private String experimentName; @@ -48,7 +46,4 @@ public void setExperimentName(String experimentName) { public interface InitialValidation { } - public interface ExperimentNameExistValidation { - } - } diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java index db4673dcc..24182259f 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java @@ -181,109 +181,108 @@ public static ListRecommendationsAPIObject convertKruizeObjectToListRecommendati } return listRecommendationsAPIObject; } - public static ListRecommendationsAPIObject convertKruizeObjectToListRecommendationSO( - KruizeObject kruizeObject, - boolean getLatest, - boolean checkForTimestamp, - String monitoringEndTimestamp) { - ListRecommendationsAPIObject listRecommendationsAPIObject = new ListRecommendationsAPIObject(); - try { - listRecommendationsAPIObject.setApiVersion(kruizeObject.getApiVersion()); - listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); - listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); - List kubernetesAPIObjects = new ArrayList<>(); - KubernetesAPIObject kubernetesAPIObject; - for (K8sObject k8sObject : kruizeObject.getKubernetes_objects()) { - kubernetesAPIObject = new KubernetesAPIObject(k8sObject.getName(), k8sObject.getType(), k8sObject.getNamespace()); - HashMap containerDataMap = new HashMap<>(); - List containerAPIObjects = new ArrayList<>(); - for (ContainerData containerData : k8sObject.getContainerDataMap().values()) { - ContainerAPIObject containerAPIObject; - // if a Time stamp is passed it holds the priority than latest - if (checkForTimestamp) { - // This step causes a performance degradation, need to be replaced with a better flow of creating SO's - ContainerData clonedContainerData = Utils.getClone(containerData, ContainerData.class); - if (null != clonedContainerData) { - HashMap>> recommendations = clonedContainerData.getContainerRecommendations().getData(); - Date medDate = Utils.DateUtils.getDateFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, monitoringEndTimestamp); - Timestamp givenTimestamp = new Timestamp(medDate.getTime()); - if (recommendations.containsKey(givenTimestamp)) { - List tempList = new ArrayList<>(); - for (Timestamp timestamp : recommendations.keySet()) { - if (!timestamp.equals(givenTimestamp)) - 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(), - new ArrayList<>(clonedContainerData.getMetrics().values())); - containerAPIObjects.add(containerAPIObject); - } - } - } else if (getLatest) { - // This step causes a performance degradation, need to be replaced with a better flow of creating SO's - containerData = getLatestRecommendations(containerData); - containerAPIObject = new ContainerAPIObject(containerData.getContainer_name(), - containerData.getContainer_image_name(), - containerData.getContainerRecommendations(), - new ArrayList<>(containerData.getMetrics().values())); - containerAPIObjects.add(containerAPIObject); - } else { - containerAPIObject = new ContainerAPIObject(containerData.getContainer_name(), - containerData.getContainer_image_name(), - containerData.getContainerRecommendations(), - new ArrayList<>(containerData.getMetrics().values())); - containerAPIObjects.add(containerAPIObject); - containerDataMap.put(containerData.getContainer_name(), containerData); - } - } - kubernetesAPIObject.setContainerAPIObjects(containerAPIObjects); - kubernetesAPIObjects.add(kubernetesAPIObject); - } - listRecommendationsAPIObject.setKubernetesObjects(kubernetesAPIObjects); - } catch (Exception e) { - e.printStackTrace(); - } - return listRecommendationsAPIObject; - } + + public static ListRecommendationsAPIObject convertKruizeObjectToListRecommendationSO( + KruizeObject kruizeObject, + boolean getLatest, + boolean checkForTimestamp, + String monitoringEndTimestamp) { + ListRecommendationsAPIObject listRecommendationsAPIObject = new ListRecommendationsAPIObject(); + try { + listRecommendationsAPIObject.setApiVersion(kruizeObject.getApiVersion()); + listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); + listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); + List kubernetesAPIObjects = new ArrayList<>(); + KubernetesAPIObject kubernetesAPIObject; + for (K8sObject k8sObject : kruizeObject.getKubernetes_objects()) { + kubernetesAPIObject = new KubernetesAPIObject(k8sObject.getName(), k8sObject.getType(), k8sObject.getNamespace()); + HashMap containerDataMap = new HashMap<>(); + List containerAPIObjects = new ArrayList<>(); + for (ContainerData containerData : k8sObject.getContainerDataMap().values()) { + ContainerAPIObject containerAPIObject; + // if a Time stamp is passed it holds the priority than latest + if (checkForTimestamp) { + // This step causes a performance degradation, need to be replaced with a better flow of creating SO's + ContainerData clonedContainerData = Utils.getClone(containerData, ContainerData.class); + if (null != clonedContainerData) { + HashMap>> recommendations = clonedContainerData.getContainerRecommendations().getData(); + Date medDate = Utils.DateUtils.getDateFrom(KruizeConstants.DateFormats.STANDARD_JSON_DATE_FORMAT, monitoringEndTimestamp); + Timestamp givenTimestamp = new Timestamp(medDate.getTime()); + if (recommendations.containsKey(givenTimestamp)) { + List tempList = new ArrayList<>(); + for (Timestamp timestamp : recommendations.keySet()) { + if (!timestamp.equals(givenTimestamp)) + 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(), + new ArrayList<>(clonedContainerData.getMetrics().values())); + containerAPIObjects.add(containerAPIObject); + } + } + } else if (getLatest) { + // This step causes a performance degradation, need to be replaced with a better flow of creating SO's + containerData = getLatestRecommendations(containerData); + containerAPIObject = new ContainerAPIObject(containerData.getContainer_name(), + containerData.getContainer_image_name(), + containerData.getContainerRecommendations(), + new ArrayList<>(containerData.getMetrics().values())); + containerAPIObjects.add(containerAPIObject); + } else { + containerAPIObject = new ContainerAPIObject(containerData.getContainer_name(), + containerData.getContainer_image_name(), + containerData.getContainerRecommendations(), + new ArrayList<>(containerData.getMetrics().values())); + containerAPIObjects.add(containerAPIObject); + containerDataMap.put(containerData.getContainer_name(), containerData); + } + } + kubernetesAPIObject.setContainerAPIObjects(containerAPIObjects); + kubernetesAPIObjects.add(kubernetesAPIObject); + } + listRecommendationsAPIObject.setKubernetesObjects(kubernetesAPIObjects); + } catch (Exception e) { + e.printStackTrace(); + } + return listRecommendationsAPIObject; + } /** - * * @param containerData * @return */ public static ContainerData getLatestRecommendations(ContainerData containerData) { - ContainerData clonedContainerData = Utils.getClone(containerData, ContainerData.class); - if (null != clonedContainerData) { - HashMap>> recommendations = clonedContainerData.getContainerRecommendations().getData(); - Timestamp latestTimestamp = null; - List tempList = new ArrayList<>(); - for (Timestamp timestamp : recommendations.keySet()) { - if (null == latestTimestamp) { - latestTimestamp = timestamp; - } else { - if (timestamp.after(latestTimestamp)) { - tempList.add(latestTimestamp); - latestTimestamp = timestamp; - } else { - tempList.add(timestamp); - } - } - } - for (Timestamp timestamp : tempList) { - recommendations.remove(timestamp); - } - clonedContainerData.getContainerRecommendations().setData(recommendations); - } - return clonedContainerData; - } + ContainerData clonedContainerData = Utils.getClone(containerData, ContainerData.class); + if (null != clonedContainerData) { + HashMap>> recommendations = clonedContainerData.getContainerRecommendations().getData(); + Timestamp latestTimestamp = null; + List tempList = new ArrayList<>(); + for (Timestamp timestamp : recommendations.keySet()) { + if (null == latestTimestamp) { + latestTimestamp = timestamp; + } else { + if (timestamp.after(latestTimestamp)) { + tempList.add(latestTimestamp); + latestTimestamp = timestamp; + } else { + tempList.add(timestamp); + } + } + } + for (Timestamp timestamp : tempList) { + recommendations.remove(timestamp); + } + clonedContainerData.getContainerRecommendations().setData(recommendations); + } + return clonedContainerData; + } /** - * * @param containerData */ public static void getLatestResults(ContainerData containerData) { @@ -316,6 +315,7 @@ public static ExperimentResultData convertUpdateResultsAPIObjToExperimentResultD experimentResultData.setIntervalStartTime(updateResultsAPIObject.getStartTimestamp()); experimentResultData.setIntervalEndTime(updateResultsAPIObject.getEndTimestamp()); experimentResultData.setExperiment_name(updateResultsAPIObject.getExperimentName()); + experimentResultData.setCluster_name(updateResultsAPIObject.getKruizeObject().getClusterName()); List kubernetesAPIObjectList = updateResultsAPIObject.getKubernetesObjects(); List k8sObjectList = new ArrayList<>(); for (KubernetesAPIObject kubernetesAPIObject : kubernetesAPIObjectList) { diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java b/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java index 43bc57867..9a9c728ec 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/UpdateResultsAPIObject.java @@ -16,6 +16,7 @@ package com.autotune.analyzer.serviceObjects; import com.autotune.analyzer.exceptions.KruizeResponse; +import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.serviceObjects.verification.annotators.CompareDate; import com.autotune.analyzer.serviceObjects.verification.annotators.KubernetesElementsCheck; import com.autotune.analyzer.serviceObjects.verification.annotators.PerformanceProfileCheck; @@ -52,6 +53,8 @@ public class UpdateResultsAPIObject extends BaseSO { private List errors; + private KruizeObject kruizeObject; + public Timestamp getStartTimestamp() { return startTimestamp; } @@ -93,12 +96,18 @@ public String toString() { '}'; } - public interface EvaluateRemainingConstraints { + public KruizeObject getKruizeObject() { + return kruizeObject; } - @GroupSequence({UpdateResultsAPIObject.class, InitialValidation.class, ExperimentNameExistValidation.class, EvaluateRemainingConstraints.class}) - public interface FullValidationSequence { + public void setKruizeObject(KruizeObject kruizeObject) { + this.kruizeObject = kruizeObject; } + public interface EvaluateRemainingConstraints { + } + @GroupSequence({UpdateResultsAPIObject.class, InitialValidation.class, EvaluateRemainingConstraints.class}) + public interface FullValidationSequence { + } } 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 deleted file mode 100644 index 8d0724ecb..000000000 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/annotators/ExperimentNameExist.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * 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/validators/CompareDateValidator.java b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/CompareDateValidator.java index caef8701e..6565113e6 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,11 +33,15 @@ public void initialize(CompareDate constraintAnnotation) { @Override public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) { boolean success = false; - if (null != updateResultsAPIObject.getStartTimestamp() && null != updateResultsAPIObject.getEndTimestamp()) { - int comparisonResult = updateResultsAPIObject.getStartTimestamp().compareTo(updateResultsAPIObject.getEndTimestamp()); - if (comparisonResult < 0) { - success = true; + try { + if (null != updateResultsAPIObject.getStartTimestamp() && null != updateResultsAPIObject.getEndTimestamp()) { + int comparisonResult = updateResultsAPIObject.getStartTimestamp().compareTo(updateResultsAPIObject.getEndTimestamp()); + if (comparisonResult < 0) { + success = true; + } } + } catch (Exception e) { + LOGGER.error(e.getMessage()); } 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 deleted file mode 100644 index c09d69def..000000000 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * 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.analyzer.services.UpdateResults; -import com.autotune.database.service.ExperimentDBService; -import jakarta.validation.ConstraintValidator; -import jakarta.validation.ConstraintValidatorContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; - -public class ExperimentNameExistValidator implements ConstraintValidator { - private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentNameExistValidator.class); - static Map mainKruizeExperimentMAP = new HashMap<>(); - - - // You can inject your database access/repository here to fetch the data - - @Override - public boolean isValid(String experimentName, ConstraintValidatorContext context) { - boolean success = false; - String errorMessage = ""; - if (!UpdateResults.mainKruizeExperimentMAP.containsKey(experimentName)) { - // Retrieve the data from the database - try { - new ExperimentDBService().loadExperimentFromDBByName(UpdateResults.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 (UpdateResults.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 index 486df2245..4b577ef42 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/KubernetesElementsValidator.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/KubernetesElementsValidator.java @@ -26,6 +26,7 @@ import jakarta.validation.ConstraintValidatorContext; public class KubernetesElementsValidator implements ConstraintValidator { + @Override public void initialize(KubernetesElementsCheck constraintAnnotation) { ConstraintValidator.super.initialize(constraintAnnotation); @@ -34,8 +35,9 @@ public void initialize(KubernetesElementsCheck constraintAnnotation) { @Override public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) { boolean success = false; + String errorMessage = ""; try { - KruizeObject kruizeObject = UpdateResults.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName()); + KruizeObject kruizeObject = updateResultsAPIObject.getKruizeObject(); PerformanceProfile performanceProfile = UpdateResults.performanceProfilesMap.get(kruizeObject.getPerformanceProfile()); ExperimentResultData resultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject); String expName = kruizeObject.getExperimentName(); @@ -95,6 +97,7 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint } else { success = true; } + } catch (Exception e) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate(e.getMessage()) 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 index 0d7f3269e..21680e33d 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java @@ -29,8 +29,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class PerformanceProfileValidator implements ConstraintValidator { @@ -48,13 +46,19 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint and then validate the Performance Profile data */ try { - KruizeObject kruizeObject = UpdateResults.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName()); + KruizeObject kruizeObject = updateResultsAPIObject.getKruizeObject(); if (UpdateResults.performanceProfilesMap.isEmpty() || !UpdateResults.performanceProfilesMap.containsKey(kruizeObject.getPerformanceProfile())) { ConcurrentHashMap tempPerformanceProfilesMap = new ConcurrentHashMap<>(); new ExperimentDBService().loadAllPerformanceProfiles(tempPerformanceProfilesMap); UpdateResults.performanceProfilesMap.putAll(tempPerformanceProfilesMap); } - PerformanceProfile performanceProfile = UpdateResults.performanceProfilesMap.get(kruizeObject.getPerformanceProfile()); + PerformanceProfile performanceProfile = null; + if (UpdateResults.performanceProfilesMap.containsKey(kruizeObject.getPerformanceProfile())) { + performanceProfile = UpdateResults.performanceProfilesMap.get(kruizeObject.getPerformanceProfile()); + } else { + throw new Exception(String.format("Not Found : Performance Profile doesn't exist - %s", kruizeObject.getPerformanceProfile())); + } + ExperimentResultData resultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject); // validate the 'resultdata' with the performance profile String errorMsg = PerformanceProfileUtil.validateResults(performanceProfile, resultData); @@ -66,10 +70,11 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint .addPropertyNode("Performance profile") .addConstraintViolation(); } + } catch (Exception e) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate(e.getMessage()) - .addPropertyNode("Performance profile") + .addPropertyNode("") .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 index 468f494e0..7c545ff5d 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 @@ -19,7 +19,6 @@ import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject; import com.autotune.analyzer.serviceObjects.verification.annotators.TimeDifferenceCheck; -import com.autotune.analyzer.services.UpdateResults; import com.autotune.common.data.result.IntervalResults; import com.autotune.utils.KruizeConstants; import jakarta.validation.ConstraintValidator; @@ -38,18 +37,25 @@ public void initialize(TimeDifferenceCheck constraintAnnotation) { @Override public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, ConstraintValidatorContext context) { boolean success = false; - - KruizeObject kruizeObject = UpdateResults.mainKruizeExperimentMAP.get(updateResultsAPIObject.getExperimentName()); - - IntervalResults intervalResults = new IntervalResults(updateResultsAPIObject.getStartTimestamp(), updateResultsAPIObject.getEndTimestamp()); - Double durationInSeconds = intervalResults.getDuration_in_seconds(); - String measurementDurationInMins = kruizeObject.getTrial_settings().getMeasurement_durationMinutes(); - Double parsedMeasurementDuration = Double.parseDouble(measurementDurationInMins.substring(0, measurementDurationInMins.length() - 3)); - // Calculate the lower and upper bounds for the acceptable range i.e. +-5 seconds - double lowerRange = Math.abs((parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) - (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS)); - double upperRange = (parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) + (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS); - if ((durationInSeconds >= lowerRange && durationInSeconds <= upperRange)) - success = true; + try { + KruizeObject kruizeObject = updateResultsAPIObject.getKruizeObject(); + IntervalResults intervalResults = new IntervalResults(updateResultsAPIObject.getStartTimestamp(), updateResultsAPIObject.getEndTimestamp()); + Double durationInSeconds = intervalResults.getDuration_in_seconds(); + String measurementDurationInMins = kruizeObject.getTrial_settings().getMeasurement_durationMinutes(); + Double parsedMeasurementDuration = Double.parseDouble(measurementDurationInMins.substring(0, measurementDurationInMins.length() - 3)); + // Calculate the lower and upper bounds for the acceptable range i.e. +-5 seconds + double lowerRange = Math.abs((parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) - (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS)); + double upperRange = (parsedMeasurementDuration * KruizeConstants.TimeConv.NO_OF_SECONDS_PER_MINUTE) + (KruizeConstants.TimeConv.MEASUREMENT_DURATION_THRESHOLD_SECONDS); + if ((durationInSeconds >= lowerRange && durationInSeconds <= upperRange)) + success = true; + } catch (Exception e) { + LOGGER.error(e.getMessage()); + e.printStackTrace(); + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(e.getMessage()) + .addPropertyNode("Time : ") + .addConstraintViolation(); + } return success; } diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index 5e1217597..85d3ea77e 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -20,7 +20,6 @@ import com.autotune.analyzer.serviceObjects.ContainerAPIObject; import com.autotune.analyzer.serviceObjects.Converters; import com.autotune.analyzer.serviceObjects.ListRecommendationsAPIObject; -import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; import com.autotune.analyzer.utils.GsonUTCDateAdapter; import com.autotune.common.data.ValidationOutputData; @@ -38,7 +37,6 @@ import io.micrometer.core.instrument.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.micrometer.core.instrument.Timer; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -48,7 +46,10 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.Timestamp; -import java.util.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -151,18 +152,18 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) List experimentResultDataList = new ArrayList<>(); ExperimentResultData experimentResultData = null; Map mainKruizeExperimentMAP = new ConcurrentHashMap<>(); + KruizeObject kruizeObject = null; try { - String clusterName = null; - if (mainKruizeExperimentMAP.containsKey(experiment_name)) { - clusterName = mainKruizeExperimentMAP.get(experiment_name).getClusterName(); - } else { - new ExperimentDBService().loadExperimentFromDBByName(mainKruizeExperimentMAP, experiment_name); - if (null != mainKruizeExperimentMAP.get(experiment_name)) { - clusterName = mainKruizeExperimentMAP.get(experiment_name).getClusterName(); - } + new ExperimentDBService().loadExperimentFromDBByName(mainKruizeExperimentMAP, experiment_name); + if (null != mainKruizeExperimentMAP.get(experiment_name)) { + kruizeObject = mainKruizeExperimentMAP.get(experiment_name); + } + if (null != kruizeObject) + experimentResultDataList = new ExperimentDBService().getExperimentResultData(experiment_name, kruizeObject, interval_start_time, interval_end_time); // Todo this object is not required + else { + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found : experiment_name doesn't exist - %s", experiment_name)); + return; } - if (null != clusterName) - experimentResultDataList = new ExperimentDBService().getExperimentResultData(experiment_name, clusterName, interval_start_time, interval_end_time); // Todo this object is not required } catch (Exception e) { sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); return; @@ -171,7 +172,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) if (experimentResultDataList.size() > 0) { //generate recommendation try { - KruizeObject kruizeObject = mainKruizeExperimentMAP.get(experiment_name); new ExperimentInitiator().generateAndAddRecommendations(kruizeObject, experimentResultDataList, interval_start_time, interval_end_time); // TODO: experimentResultDataList not required ValidationOutputData validationOutputData = new ExperimentDBService().addRecommendationToDB(mainKruizeExperimentMAP, experimentResultDataList); if (validationOutputData.isSuccess()) { @@ -191,10 +191,10 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } } else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, AnalyzerErrorConstants.APIErrors.UpdateRecommendationsAPI.DATA_NOT_FOUND); + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found : interval_end_time doesn't exist - %s", intervalEndTimeStr)); return; } - }catch (Exception e){ + } catch (Exception e) { LOGGER.error("Exception: " + e.getMessage()); e.printStackTrace(); sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); @@ -253,6 +253,7 @@ public boolean shouldSkipClass(Class clazz) { public void sendErrorResponse(HttpServletResponse response, Exception e, int httpStatusCode, String errorMsg) throws IOException { if (null != e) { + e.printStackTrace(); LOGGER.error(e.toString()); if (null == errorMsg) errorMsg = e.getMessage(); } diff --git a/src/main/java/com/autotune/analyzer/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index 062f7f231..54b34ec05 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -18,7 +18,6 @@ import com.autotune.analyzer.exceptions.KruizeResponse; import com.autotune.analyzer.experiment.ExperimentInitiator; -import com.autotune.analyzer.kruizeObject.KruizeObject; import com.autotune.analyzer.performanceProfiles.PerformanceProfile; import com.autotune.analyzer.serviceObjects.FailedUpdateResultsAPIObject; import com.autotune.analyzer.serviceObjects.UpdateResultsAPIObject; @@ -29,7 +28,6 @@ import com.autotune.utils.MetricsConfig; import com.google.gson.Gson; import io.micrometer.core.instrument.Timer; -import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +42,6 @@ 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; @@ -59,7 +56,6 @@ public class UpdateResults extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger LOGGER = LoggerFactory.getLogger(UpdateResults.class); public static ConcurrentHashMap performanceProfilesMap = new ConcurrentHashMap<>(); - public static ConcurrentHashMap mainKruizeExperimentMAP; @Override public void init(ServletConfig config) throws ServletException { @@ -70,7 +66,6 @@ public void init(ServletConfig config) throws ServletException { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String statusValue = "failure"; Timer.Sample timerUpdateResults = Timer.start(MetricsConfig.meterRegistry()); - mainKruizeExperimentMAP = new ConcurrentHashMap(); try { String inputData = request.getReader().lines().collect(Collectors.joining()); List experimentResultDataList = new ArrayList<>(); diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java index 7a521d056..d82cfd82b 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -75,7 +75,7 @@ public static final class AutotuneObjectErrors { public static final String MISSING_SLO_DATA = "No Performance Profile or SLO data is Present!"; 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 MISSING_PERF_PROFILE = "Not Found : performance_profile doesn't exist - "; 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!"; diff --git a/src/main/java/com/autotune/common/data/result/ExperimentResultData.java b/src/main/java/com/autotune/common/data/result/ExperimentResultData.java index 44905b074..94d7950bf 100644 --- a/src/main/java/com/autotune/common/data/result/ExperimentResultData.java +++ b/src/main/java/com/autotune/common/data/result/ExperimentResultData.java @@ -41,6 +41,8 @@ public class ExperimentResultData { private ValidationOutputData validationOutputData; private List kubernetes_objects; + private String cluster_name; + public String getExperiment_name() { return experiment_name; @@ -141,4 +143,12 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(experiment_name, intervalEndTime); } + + public String getCluster_name() { + return cluster_name; + } + + public void setCluster_name(String cluster_name) { + this.cluster_name = cluster_name; + } } diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index 369b2030b..a264f841c 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -31,6 +31,8 @@ import java.util.List; import java.util.stream.IntStream; +import static com.autotune.database.helper.DBConstants.DB_MESSAGES.DUPLICATE_KEY; +import static com.autotune.database.helper.DBConstants.DB_MESSAGES.DUPLICATE_KEY_ALT; import static com.autotune.database.helper.DBConstants.SQLQUERY.*; public class ExperimentDAOImpl implements ExperimentDAO { @@ -90,11 +92,11 @@ public void addPartitions(String tableName, String month, String year, int dayOf session.createNativeQuery(daterange).executeUpdate(); }); } else if (partitionType.equalsIgnoreCase(DBConstants.PARTITION_TYPES.BY_15_DAYS)) { - IntStream.range(1, 16).forEach(i -> { - String daterange = String.format(DB_PARTITION_DATERANGE, tableName, year, month, String.format("%02d", i), tableName, - year, month, String.format("%02d", i), year, month, String.format("%02d", i)); - session.createNativeQuery(daterange).executeUpdate(); - }); + IntStream.range(1, 16).forEach(i -> { + String daterange = String.format(DB_PARTITION_DATERANGE, tableName, year, month, String.format("%02d", i), tableName, + year, month, String.format("%02d", i), year, month, String.format("%02d", i)); + session.createNativeQuery(daterange).executeUpdate(); + }); } else if (partitionType.equalsIgnoreCase(DBConstants.PARTITION_TYPES.BY_DAY)) { String daterange = String.format(DB_PARTITION_DATERANGE, tableName, year, month, String.format("%02d", 1), tableName, year, month, String.format("%02d", 1), year, month, String.format("%02d", 1)); @@ -166,10 +168,16 @@ public List addToDBAndFetchFailedResults(List addToDBAndFetchFailedResults(List mainKruizeExperime if (null != updateResultsAPIObjects && !updateResultsAPIObjects.isEmpty()) { List resultDataList = new ArrayList<>(); for (UpdateResultsAPIObject updateResultsAPIObject : updateResultsAPIObjects) { + updateResultsAPIObject.setKruizeObject(kruizeObject); try { ExperimentResultData experimentResultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject); if (experimentResultData != null) @@ -204,11 +205,16 @@ public ValidationOutputData addExperimentToDB(CreateExperimentAPIObject createEx public List addResultsToDB(List resultDataList) { List kruizeResultsEntryList = new ArrayList<>(); List failedUpdateResultsAPIObjects = new ArrayList<>(); + List failedResultsEntries = new ArrayList<>(); for (ExperimentResultData resultData : resultDataList) { KruizeResultsEntry kruizeResultsEntry = DBHelpers.Converters.KruizeObjectConverters.convertExperimentResultToExperimentResultsTable(resultData); - kruizeResultsEntryList.add(kruizeResultsEntry); + if (null != kruizeResultsEntry.getErrorReasons() && kruizeResultsEntry.getErrorReasons().size() > 0) { + failedResultsEntries.add(kruizeResultsEntry); + } else { + kruizeResultsEntryList.add(kruizeResultsEntry); + } } - List failedResultsEntries = experimentDAO.addToDBAndFetchFailedResults(kruizeResultsEntryList); + failedResultsEntries.addAll(experimentDAO.addToDBAndFetchFailedResults(kruizeResultsEntryList)); failedUpdateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(failedResultsEntries); return failedUpdateResultsAPIObjects; } @@ -342,12 +348,13 @@ public boolean updateExperimentStatus(KruizeObject kruizeObject, AnalyzerConstan } - public List getExperimentResultData(String experiment_name, String clusterName, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { + public List getExperimentResultData(String experiment_name, KruizeObject kruizeObject, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { List experimentResultDataList = new ArrayList<>(); - List kruizeResultsEntryList = experimentDAO.getKruizeResultsEntry(experiment_name, clusterName, interval_start_time, interval_end_time); + List kruizeResultsEntryList = experimentDAO.getKruizeResultsEntry(experiment_name, kruizeObject.getClusterName(), interval_start_time, interval_end_time); if (null != kruizeResultsEntryList) { List updateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(kruizeResultsEntryList); for (UpdateResultsAPIObject updateObject : updateResultsAPIObjects) { + updateObject.setKruizeObject(kruizeObject); experimentResultDataList.add( Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateObject) ); From 0f2f0fb74fbb967bd0bab85c1378d334d2951196 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Wed, 20 Sep 2023 21:00:20 +0530 Subject: [PATCH 12/36] MD file for retry information Signed-off-by: msvinaykumar --- design/MonitoringModeAPI.md | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index 18365e739..7d90cd0c0 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -2463,3 +2463,125 @@ Example Response Body: | 400 | The Start time should precede the End time! | | | 500 | Internal Server Error | +--- + +## Implementing Retry Mechanism for Kruize API Consumers + +When consuming a REST API, it's essential to handle scenarios where the API may respond with errors or encounter +temporary issues such as a 504 Gateway Timeout. To ensure robustness and reliability, implementing a retry mechanism +with exponential backoff is a good practice. In this guide, we'll discuss how to implement a retry mechanism with at +least three attempts for the following scenarios: + +```POST /createExperiment``` + +If the API responds with "Profile Name not found," implement retry logic. + +``` +{ + "message": "Performance Profile doesn't exist : resource-optimization-openshift", + "httpcode": 400, + "documentationLink": "", + "status": "ERROR" +} +``` + +```POST /updateResults``` + +If the API responds with: + +- "Experiment_name not found" +- "Profile_name not found" + +Implement retry logic. + +``` +{ + "message": "Out of a total of 2 records, 1 failed to save", + "httpcode": 400, + "documentationLink": "", + "status": "ERROR", + "data": [ + { + "interval_start_time": "2023-04-01T00:00:00.000Z", + "interval_end_time": "2023-04-01T00:15:00.000Z", + "errors": [ + { + "message": "Not Found : experiment_name doesn't exist - quarkus-resteasy-kruize-min-http-response-time-db_1_1_1", + "httpcode": 400, + "documentationLink": "", + "status": "ERROR" + } + ], + "version": "3.0", + "experiment_name": "quarkus-resteasy-kruize-min-http-response-time-db_1_1_1" + } + ] +} +``` + +``` +{ + "message": "Out of a total of 2 records, 1 failed to save", + "httpcode": 400, + "documentationLink": "", + "status": "ERROR", + "data": [ + { + "interval_start_time": "2023-04-01T00:00:00.000Z", + "interval_end_time": "2023-04-01T00:15:00.000Z", + "errors": [ + { + "message": "Not Found : Performance Profile doesn't exist - resource-optimization-openshift", + "httpcode": 400, + "documentationLink": "", + "status": "ERROR" + } + ], + "version": "3.0", + "experiment_name": "quarkus-resteasy-kruize-min-http-response-time-db_1_1" + } + ] +} +``` + +```POST /updateRecommendations?interval_end_time=&experiment_name=``` + +If the API responds with: + +- "Experiment_name not found" +- "interval_end_time not found" + +Implement retry logic. + +``` +{ + "message": "Not Found : experiment_name doesn't exist - quarkus-resteasy-kruize-min-http-response-time-db_1_2", + "httpcode": 400, + "documentationLink": "", + "status": "ERROR" +} +``` + +``` +{ + "message": "Not Found : interval_end_time doesn't exist - 2023-02-02T00:00:00.000Z", + "httpcode": 400, + "documentationLink": "", + "status": "ERROR" +} +``` + +```POST /*``` + +- Common Scenario + +If any of the APIs respond with a "504 Gateway Timeout" error, implement retry logic. + +**Retry Mechanism with Exponential Backoff** + +The retry mechanism should follow these steps: + +- Send the initial API request. +- If the response indicates an error condition (as mentioned above), initiate the retry logic. +- Perform a maximum of three retry attempts. +- Use exponential backoff with jitter to determine the delay before each retry. From a2185f9772706da55d1e7aacef8e186594320359 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 21 Sep 2023 12:50:19 +0530 Subject: [PATCH 13/36] Not found message changed as per review Signed-off-by: msvinaykumar --- design/MonitoringModeAPI.md | 8 ++++---- .../autotune/analyzer/experiment/ExperimentInitiator.java | 2 +- .../validators/PerformanceProfileValidator.java | 2 +- .../autotune/analyzer/services/UpdateRecommendations.java | 4 ++-- .../autotune/analyzer/utils/AnalyzerErrorConstants.java | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index 7d90cd0c0..0d505956e 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -2478,7 +2478,7 @@ If the API responds with "Profile Name not found," implement retry logic. ``` { - "message": "Performance Profile doesn't exist : resource-optimization-openshift", + "message": "Not Found:performance_profile does not exist:resource-optimization-openshift", "httpcode": 400, "documentationLink": "", "status": "ERROR" @@ -2506,7 +2506,7 @@ Implement retry logic. "interval_end_time": "2023-04-01T00:15:00.000Z", "errors": [ { - "message": "Not Found : experiment_name doesn't exist - quarkus-resteasy-kruize-min-http-response-time-db_1_1_1", + "message": "Not Found:experiment_name does not exist:quarkus-resteasy-kruize-min-http-response-time-db_1_1_1", "httpcode": 400, "documentationLink": "", "status": "ERROR" @@ -2531,7 +2531,7 @@ Implement retry logic. "interval_end_time": "2023-04-01T00:15:00.000Z", "errors": [ { - "message": "Not Found : Performance Profile doesn't exist - resource-optimization-openshift", + "message": "Not Found:Performance Profile does not exist:resource-optimization-openshift", "httpcode": 400, "documentationLink": "", "status": "ERROR" @@ -2555,7 +2555,7 @@ Implement retry logic. ``` { - "message": "Not Found : experiment_name doesn't exist - quarkus-resteasy-kruize-min-http-response-time-db_1_2", + "message": "Not Found:experiment_name does not exist:quarkus-resteasy-kruize-min-http-response-time-db_1_2", "httpcode": 400, "documentationLink": "", "status": "ERROR" diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java index acaa44adc..ad7e5dd25 100644 --- a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java +++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java @@ -171,7 +171,7 @@ public void validateAndAddExperimentResults(List updateR } } else { List errorReasons = new ArrayList<>(); - errorReasons.add(String.format("Not Found : experiment_name doesn't exist - %s", experimentName)); + errorReasons.add(String.format("Not Found:experiment_name does not exist:%s", experimentName)); object.setErrors(getErrorMap(errorReasons)); failedUpdateResultsAPIObjects.add(object); } 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 index 21680e33d..7bdf6ed00 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java @@ -56,7 +56,7 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint if (UpdateResults.performanceProfilesMap.containsKey(kruizeObject.getPerformanceProfile())) { performanceProfile = UpdateResults.performanceProfilesMap.get(kruizeObject.getPerformanceProfile()); } else { - throw new Exception(String.format("Not Found : Performance Profile doesn't exist - %s", kruizeObject.getPerformanceProfile())); + throw new Exception(String.format("Not Found:performance_profile does not exist:%s", kruizeObject.getPerformanceProfile())); } ExperimentResultData resultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject); diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index 85d3ea77e..01d503278 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -161,7 +161,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) if (null != kruizeObject) experimentResultDataList = new ExperimentDBService().getExperimentResultData(experiment_name, kruizeObject, interval_start_time, interval_end_time); // Todo this object is not required else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found : experiment_name doesn't exist - %s", experiment_name)); + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found:experiment_name does not exist:%s", experiment_name)); return; } } catch (Exception e) { @@ -191,7 +191,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } } else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found : interval_end_time doesn't exist - %s", intervalEndTimeStr)); + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found:interval_end_time does not exist:%s", intervalEndTimeStr)); return; } } 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 d82cfd82b..508bf8448 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -75,7 +75,7 @@ public static final class AutotuneObjectErrors { public static final String MISSING_SLO_DATA = "No Performance Profile or SLO data is Present!"; 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 = "Not Found : performance_profile doesn't exist - "; + public static final String MISSING_PERF_PROFILE = "Not Found:performance_profile does not exist:"; 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!"; From 4bf4f57e016386951d341a919071646204002f79 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 21 Sep 2023 13:04:23 +0530 Subject: [PATCH 14/36] moved to constant Signed-off-by: msvinaykumar --- .../autotune/analyzer/experiment/ExperimentInitiator.java | 4 +++- .../validators/PerformanceProfileValidator.java | 4 +++- .../autotune/analyzer/services/UpdateRecommendations.java | 6 ++++-- .../com/autotune/analyzer/utils/AnalyzerErrorConstants.java | 2 ++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java index ad7e5dd25..f2bce065e 100644 --- a/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java +++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentInitiator.java @@ -40,6 +40,8 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import static com.autotune.analyzer.utils.AnalyzerErrorConstants.AutotuneObjectErrors.MISSING_EXPERIMENT_NAME; + /** * Initiates new experiment data validations and push into queue for worker to * execute task. @@ -171,7 +173,7 @@ public void validateAndAddExperimentResults(List updateR } } else { List errorReasons = new ArrayList<>(); - errorReasons.add(String.format("Not Found:experiment_name does not exist:%s", experimentName)); + errorReasons.add(String.format("%s%s", MISSING_EXPERIMENT_NAME, experimentName)); object.setErrors(getErrorMap(errorReasons)); failedUpdateResultsAPIObjects.add(object); } 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 index 7bdf6ed00..a34de275b 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/PerformanceProfileValidator.java @@ -31,6 +31,8 @@ import java.util.concurrent.ConcurrentHashMap; +import static com.autotune.analyzer.utils.AnalyzerErrorConstants.AutotuneObjectErrors.MISSING_PERF_PROFILE; + public class PerformanceProfileValidator implements ConstraintValidator { private static final Logger LOGGER = LoggerFactory.getLogger(PerformanceProfileValidator.class); @@ -56,7 +58,7 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint if (UpdateResults.performanceProfilesMap.containsKey(kruizeObject.getPerformanceProfile())) { performanceProfile = UpdateResults.performanceProfilesMap.get(kruizeObject.getPerformanceProfile()); } else { - throw new Exception(String.format("Not Found:performance_profile does not exist:%s", kruizeObject.getPerformanceProfile())); + throw new Exception(String.format("%s%s", MISSING_PERF_PROFILE, kruizeObject.getPerformanceProfile())); } ExperimentResultData resultData = Converters.KruizeObjectConverters.convertUpdateResultsAPIObjToExperimentResultData(updateResultsAPIObject); diff --git a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java index 01d503278..09ef82beb 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateRecommendations.java @@ -55,6 +55,8 @@ import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.CHARACTER_ENCODING; import static com.autotune.analyzer.utils.AnalyzerConstants.ServiceConstants.JSON_CONTENT_TYPE; +import static com.autotune.analyzer.utils.AnalyzerErrorConstants.AutotuneObjectErrors.MISSING_EXPERIMENT_NAME; +import static com.autotune.analyzer.utils.AnalyzerErrorConstants.AutotuneObjectErrors.MISSING_INTERVAL_END_TIME; /** * @@ -161,7 +163,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) if (null != kruizeObject) experimentResultDataList = new ExperimentDBService().getExperimentResultData(experiment_name, kruizeObject, interval_start_time, interval_end_time); // Todo this object is not required else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found:experiment_name does not exist:%s", experiment_name)); + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("%s%s", MISSING_EXPERIMENT_NAME, experiment_name)); return; } } catch (Exception e) { @@ -191,7 +193,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } } else { - sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("Not Found:interval_end_time does not exist:%s", intervalEndTimeStr)); + sendErrorResponse(response, null, HttpServletResponse.SC_BAD_REQUEST, String.format("%s%s", MISSING_INTERVAL_END_TIME, intervalEndTimeStr)); return; } } 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 508bf8448..35c373cdd 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -76,6 +76,8 @@ 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 = "Not Found:performance_profile does not exist:"; + public static final String MISSING_EXPERIMENT_NAME = "Not Found:experiment_name does not exist:"; + public static final String MISSING_INTERVAL_END_TIME = "Not Found:interval_end_time does not exist:"; 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!"; From fd1293118f98ef5a0567dbe8b535c5188673a320 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 21 Sep 2023 14:35:19 +0530 Subject: [PATCH 15/36] review comments incorporated Signed-off-by: msvinaykumar --- design/MonitoringModeAPI.md | 10 +++++----- .../openshift/kruize-crc-openshift.yaml | 2 +- .../analyzer/utils/AnalyzerErrorConstants.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index 0d505956e..92e4cf05a 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -2478,7 +2478,7 @@ If the API responds with "Profile Name not found," implement retry logic. ``` { - "message": "Not Found:performance_profile does not exist:resource-optimization-openshift", + "message": "Not Found: performance_profile does not exist: resource-optimization-openshift", "httpcode": 400, "documentationLink": "", "status": "ERROR" @@ -2506,7 +2506,7 @@ Implement retry logic. "interval_end_time": "2023-04-01T00:15:00.000Z", "errors": [ { - "message": "Not Found:experiment_name does not exist:quarkus-resteasy-kruize-min-http-response-time-db_1_1_1", + "message": "Not Found: experiment_name does not exist: quarkus-resteasy-kruize-min-http-response-time-db_1_1_1", "httpcode": 400, "documentationLink": "", "status": "ERROR" @@ -2531,7 +2531,7 @@ Implement retry logic. "interval_end_time": "2023-04-01T00:15:00.000Z", "errors": [ { - "message": "Not Found:Performance Profile does not exist:resource-optimization-openshift", + "message": "Not Found: performance_profile does not exist: resource-optimization-openshift", "httpcode": 400, "documentationLink": "", "status": "ERROR" @@ -2555,7 +2555,7 @@ Implement retry logic. ``` { - "message": "Not Found:experiment_name does not exist:quarkus-resteasy-kruize-min-http-response-time-db_1_2", + "message": "Not Found: experiment_name does not exist: quarkus-resteasy-kruize-min-http-response-time-db_1_2", "httpcode": 400, "documentationLink": "", "status": "ERROR" @@ -2564,7 +2564,7 @@ Implement retry logic. ``` { - "message": "Not Found : interval_end_time doesn't exist - 2023-02-02T00:00:00.000Z", + "message": "Not Found: interval_end_time does not exist: 2023-02-02T00:00:00.000Z", "httpcode": 400, "documentationLink": "", "status": "ERROR" diff --git a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml index b5fb365c4..e1d2e7f45 100644 --- a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml @@ -176,7 +176,7 @@ metadata: app: kruize namespace: openshift-tuning spec: - replicas: 10 + replicas: 1 selector: matchLabels: name: kruize diff --git a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java index 35c373cdd..6f3fa013e 100644 --- a/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java +++ b/src/main/java/com/autotune/analyzer/utils/AnalyzerErrorConstants.java @@ -75,9 +75,9 @@ public static final class AutotuneObjectErrors { public static final String MISSING_SLO_DATA = "No Performance Profile or SLO data is Present!"; 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 = "Not Found:performance_profile does not exist:"; - public static final String MISSING_EXPERIMENT_NAME = "Not Found:experiment_name does not exist:"; - public static final String MISSING_INTERVAL_END_TIME = "Not Found:interval_end_time does not exist:"; + public static final String MISSING_PERF_PROFILE = "Not Found: performance_profile does not exist: "; + public static final String MISSING_EXPERIMENT_NAME = "Not Found: experiment_name does not exist: "; + public static final String MISSING_INTERVAL_END_TIME = "Not Found: interval_end_time does not exist: "; 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!"; From bc787694fe3a23b7acde5cbc4d1cc428e3822cec Mon Sep 17 00:00:00 2001 From: saakhan Date: Thu, 21 Sep 2023 17:08:31 +0530 Subject: [PATCH 16/36] add cron job for partition creation Signed-off-by: saakhan --- .../minikube/kruize-crc-minikube.yaml | 40 +++++++++++++++ .../openshift/kruize-crc-openshift.yaml | 40 +++++++++++++++ pom.xml | 4 ++ scripts/common_utils.sh | 5 +- src/main/java/com/autotune/Autotune.java | 7 ++- .../database/dao/ExperimentDAOImpl.java | 49 +++++++++++++------ .../autotune/database/helper/DBConstants.java | 2 + .../com/autotune/jobs/CreatePartition.java | 46 ++++++++++++++--- 8 files changed, 170 insertions(+), 23 deletions(-) diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index feb2c31e2..c4b6f0575 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -195,6 +195,46 @@ spec: port: 8080 targetPort: 8080 --- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: create-partition-cronjob +spec: + schedule: "0 0 25 * *" # Run on 25th of every month at midnight + jobTemplate: + spec: + template: + spec: + containers: + - name: kruizecronjob + image: kruize/autotune_operator:0.0.19_rm + imagePullPolicy: Always + volumeMounts: + - name: config-volume + mountPath: /etc/config + command: + - sh + - -c + - | + chmod +x /home/autotune/app/target/bin/CreatePartition && /home/autotune/app/target/bin/CreatePartition + args: [ "" ] + env: + - name: START_AUTOTUNE + value: "false" + - name: LOGGING_LEVEL + value: "info" + - name: ROOT_LOGGING_LEVEL + value: "error" + - name: DB_CONFIG_FILE + value: "/etc/config/dbconfigjson" + - name: KRUIZE_CONFIG_FILE + value: "/etc/config/kruizeconfigjson" + volumes: + - name: config-volume + configMap: + name: kruizeconfig + restartPolicy: OnFailure +--- apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: diff --git a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml index e1d2e7f45..c93640073 100644 --- a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml @@ -248,6 +248,46 @@ spec: port: 8080 targetPort: 8080 --- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: create-partition-cronjob +spec: + schedule: "0 0 25 * *" # Run on 25th of every month at midnight + jobTemplate: + spec: + template: + spec: + containers: + - name: kruizecronjob + image: kruize/autotune_operator:0.0.19_rm + imagePullPolicy: Always + volumeMounts: + - name: config-volume + mountPath: /etc/config + command: + - sh + - -c + - | + chmod +x /home/autotune/app/target/bin/CreatePartition && /home/autotune/app/target/bin/CreatePartition + args: [ "" ] + env: + - name: START_AUTOTUNE + value: "false" + - name: LOGGING_LEVEL + value: "info" + - name: ROOT_LOGGING_LEVEL + value: "error" + - name: DB_CONFIG_FILE + value: "/etc/config/dbconfigjson" + - name: KRUIZE_CONFIG_FILE + value: "/etc/config/kruizeconfigjson" + volumes: + - name: config-volume + configMap: + name: kruizeconfig + restartPolicy: OnFailure +--- apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: diff --git a/pom.xml b/pom.xml index f9266c548..5376d9d90 100644 --- a/pom.xml +++ b/pom.xml @@ -187,6 +187,10 @@ com.autotune.Autotune Autotune + + com.autotune.jobs.CreatePartition + CreatePartition + diff --git a/scripts/common_utils.sh b/scripts/common_utils.sh index 3e75ac3a5..82264ebe7 100755 --- a/scripts/common_utils.sh +++ b/scripts/common_utils.sh @@ -96,7 +96,10 @@ kruize_crc_start() { if ($2=="name:") { prev=$3; print - } else if ($1=="image:" && prev=="kruize") { + } else if ($1=="image:" && prev=="kruizecronjob") { + $2=image_name; + printf" %s %s\n", $1, $2; + } else if ($1=="image:" && prev=="kruize") { $2=image_name; printf" %s %s\n", $1, $2; } else if ($1=="image:" && prev=="kruize-ui-nginx-container") { diff --git a/src/main/java/com/autotune/Autotune.java b/src/main/java/com/autotune/Autotune.java index c4710769d..029f84ea9 100644 --- a/src/main/java/com/autotune/Autotune.java +++ b/src/main/java/com/autotune/Autotune.java @@ -125,8 +125,11 @@ public static void main(String[] args) { } try { - server.start(); - server.join(); + String startAutotune = System.getenv("START_AUTOTUNE"); + if (startAutotune == null || startAutotune.equalsIgnoreCase("true")) { + server.start(); + server.join(); + } } catch (Exception e) { LOGGER.error("Could not start the server!"); e.printStackTrace(); diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index a264f841c..cd532b69d 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -26,7 +26,7 @@ import java.sql.Timestamp; import java.time.LocalDateTime; import java.time.YearMonth; -import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.stream.IntStream; @@ -79,7 +79,7 @@ public void addPartitions(String tableName, String month, String year, int dayOf Transaction tx; try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { tx = session.beginTransaction(); - // Create a YearMonth object and get the current month and current year + // Create a YearMonth object YearMonth yearMonth = YearMonth.of(Integer.parseInt(year), Integer.parseInt(month)); // check the partition type and create corresponding query @@ -186,17 +186,40 @@ public List addToDBAndFetchFailedResults(List 12) { + month = 1; + year += 1; + } + addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RESULTS, String.format("%02d", month),String.valueOf(year), 1, DBConstants.PARTITION_TYPES.BY_MONTH); + addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RECOMMENDATIONS, String.format("%02d", month),String.valueOf(year), 1, DBConstants.PARTITION_TYPES.BY_MONTH); + } session.persist(entry); session.flush(); } catch (Exception partitionException) { @@ -218,8 +241,6 @@ public List addToDBAndFetchFailedResults(List 12) { + month = 1; + year += 1; + } + String formattedMonth = String.format("%02d", month); + String formattedYear = String.valueOf(year); + // Fixing the partition type to 'by_month' + new ExperimentDAOImpl().addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RESULTS, formattedMonth,formattedYear, 1, DBConstants.PARTITION_TYPES.BY_MONTH); + new ExperimentDAOImpl().addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RECOMMENDATIONS, formattedMonth, formattedYear, 1, DBConstants.PARTITION_TYPES.BY_MONTH); + statusValue = "success"; + tx.commit(); + LOGGER.info("Partition creation successful!"); + } catch (Exception partitionException) { + LOGGER.error(partitionException.getMessage()); + tx.commit(); + } finally { + if (null != timerAddBulkResultsDB) { + MetricsConfig.timerAddBulkResultsDB = MetricsConfig.timerBAddBulkResultsDB.tag("status", statusValue).register(MetricsConfig.meterRegistry()); + timerAddBulkResultsDB.stop(MetricsConfig.timerAddBulkResultsDB); + } + } + } catch (Exception | K8sTypeNotSupportedException | MonitoringAgentNotSupportedException | MonitoringAgentNotFoundException e) { e.printStackTrace(); System.exit(1); } - SessionFactory factory = KruizeHibernateUtil.getSessionFactory(); - - Session session = factory.openSession(); - - session.close(); LOGGER.info("DB Liveliness probe connection successful!"); } } From c70ead8d6ab57c30541460acfc44090fc322fae9 Mon Sep 17 00:00:00 2001 From: saakhan Date: Thu, 21 Sep 2023 20:32:22 +0530 Subject: [PATCH 17/36] update logic to add prev 15 days partitions in case of 25th or later and other refactoring Signed-off-by: saakhan --- scripts/common_utils.sh | 12 +-- .../database/dao/ExperimentDAOImpl.java | 85 +++++++++++-------- .../com/autotune/jobs/CreatePartition.java | 15 +--- 3 files changed, 59 insertions(+), 53 deletions(-) diff --git a/scripts/common_utils.sh b/scripts/common_utils.sh index 82264ebe7..ab4c2c0e7 100755 --- a/scripts/common_utils.sh +++ b/scripts/common_utils.sh @@ -97,16 +97,16 @@ kruize_crc_start() { prev=$3; print } else if ($1=="image:" && prev=="kruizecronjob") { - $2=image_name; - printf" %s %s\n", $1, $2; - } else if ($1=="image:" && prev=="kruize") { + $2=image_name; + printf" %s %s\n", $1, $2; + } else if ($1=="image:" && prev=="kruize") { $2=image_name; printf" %s %s\n", $1, $2; } else if ($1=="image:" && prev=="kruize-ui-nginx-container") { - $2=ui_image_name; - printf" %s %s\n", $1, $2; + $2=ui_image_name; + printf" %s %s\n", $1, $2; } else { print } - }' ${CRC_MANIFEST_FILE_OLD} >${CRC_MANIFEST_FILE} + }' ${CRC_MANIFEST_FILE_OLD} >${CRC_MANIFEST_FILE} ${kubectl_cmd} apply -f ${CRC_MANIFEST_FILE} check_running kruize ${autotune_ns} kruize-ui if [ "${err}" != "0" ]; then diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index cd532b69d..017b77287 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -185,41 +185,8 @@ public List addToDBAndFetchFailedResults(List 12) { - month = 1; - year += 1; - } - addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RESULTS, String.format("%02d", month),String.valueOf(year), 1, DBConstants.PARTITION_TYPES.BY_MONTH); - addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RECOMMENDATIONS, String.format("%02d", month),String.valueOf(year), 1, DBConstants.PARTITION_TYPES.BY_MONTH); - } + // create partitions based on entry object + createPartitions(entry); session.persist(entry); session.flush(); } catch (Exception partitionException) { @@ -257,6 +224,43 @@ public List addToDBAndFetchFailedResults(List getKruizeResultsEntry(String experiment_name, St } return kruizeResultsEntryList; } + + public YearMonth buildDateForNextMonth(YearMonth yearMonth) { + int year = yearMonth.getYear(); + int month = yearMonth.getMonthValue() + 1; // increment by one as we need to create the partition for the next month + if (month > 12) { + month = 1; + year += 1; + } + yearMonth = YearMonth.of(year, month); + return yearMonth; + } } diff --git a/src/main/java/com/autotune/jobs/CreatePartition.java b/src/main/java/com/autotune/jobs/CreatePartition.java index b2ba14a55..ff6498abf 100644 --- a/src/main/java/com/autotune/jobs/CreatePartition.java +++ b/src/main/java/com/autotune/jobs/CreatePartition.java @@ -27,23 +27,14 @@ public static void main(String[] args) { Timer.Sample timerAddBulkResultsDB = Timer.start(MetricsConfig.meterRegistry()); try { InitializeDeployment.setup_deployment_info(); - // create partitions try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { tx = session.beginTransaction(); // Get the current year and month - YearMonth yearMonth = YearMonth.now(); - int year = yearMonth.getYear(); - int month = yearMonth.getMonthValue() + 1; // increment by one as we need to create the partition for the next month - if (month > 12) { - month = 1; - year += 1; - } - String formattedMonth = String.format("%02d", month); - String formattedYear = String.valueOf(year); + YearMonth yearMonth = new ExperimentDAOImpl().buildDateForNextMonth(YearMonth.now()); // Fixing the partition type to 'by_month' - new ExperimentDAOImpl().addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RESULTS, formattedMonth,formattedYear, 1, DBConstants.PARTITION_TYPES.BY_MONTH); - new ExperimentDAOImpl().addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RECOMMENDATIONS, formattedMonth, formattedYear, 1, DBConstants.PARTITION_TYPES.BY_MONTH); + new ExperimentDAOImpl().addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RESULTS, String.format("%02d", yearMonth.getMonthValue()),String.valueOf(yearMonth.getYear()), 1, DBConstants.PARTITION_TYPES.BY_MONTH); + new ExperimentDAOImpl().addPartitions(DBConstants.TABLE_NAMES.KRUIZE_RECOMMENDATIONS, String.format("%02d", yearMonth.getMonthValue()),String.valueOf(yearMonth.getYear()), 1, DBConstants.PARTITION_TYPES.BY_MONTH); statusValue = "success"; tx.commit(); LOGGER.info("Partition creation successful!"); From dbe82ba5137d564f584879a83fe7ad7d4209293c Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 26 Sep 2023 12:31:38 +0530 Subject: [PATCH 18/36] fixed when cluster_name is null Signed-off-by: msvinaykumar --- .../database/dao/ExperimentDAOImpl.java | 44 ++++++++++++------- .../autotune/database/helper/DBConstants.java | 30 +++++++------ 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index 017b77287..b0cc5f08e 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -34,6 +34,7 @@ import static com.autotune.database.helper.DBConstants.DB_MESSAGES.DUPLICATE_KEY; import static com.autotune.database.helper.DBConstants.DB_MESSAGES.DUPLICATE_KEY_ALT; import static com.autotune.database.helper.DBConstants.SQLQUERY.*; +import static com.autotune.utils.KruizeConstants.JSONKeys.CLUSTER_NAME; public class ExperimentDAOImpl implements ExperimentDAO { private static final long serialVersionUID = 1L; @@ -505,13 +506,20 @@ public List loadResultsByExperimentName(String experimentNam // TODO: load only experimentStatus=inProgress , playback may not require completed experiments List kruizeResultsEntries = null; String statusValue = "failure"; + String clusterCondtionSql = ""; + if (cluster_name != null) + clusterCondtionSql = String.format(" and k.%s = :%s ", KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.CLUSTER_NAME); + else + clusterCondtionSql = String.format(" and k.%s is null ", KruizeConstants.JSONKeys.CLUSTER_NAME); Timer.Sample timerLoadResultsExpName = Timer.start(MetricsConfig.meterRegistry()); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { if (null != limitRows && null != interval_end_time) { - kruizeResultsEntries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT, KruizeResultsEntry.class) - .setParameter(KruizeConstants.JSONKeys.CLUSTER_NAME, cluster_name) + Query kruizeResultsEntryQuery = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT + clusterCondtionSql + " ORDER BY k.interval_end_time DESC ", KruizeResultsEntry.class) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName) - .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) + .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time); + if (cluster_name != null) + kruizeResultsEntryQuery.setParameter(CLUSTER_NAME, cluster_name); + kruizeResultsEntries = kruizeResultsEntryQuery .setMaxResults(limitRows) .list(); statusValue = "success"; @@ -560,7 +568,7 @@ public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(Stri Timer.Sample timerLoadRecExpNameDate = Timer.start(MetricsConfig.meterRegistry()); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { recommendationEntries = session.createQuery(SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME_AND_END_TIME, KruizeRecommendationEntry.class) - .setParameter(KruizeConstants.JSONKeys.CLUSTER_NAME, cluster_name) + .setParameter(CLUSTER_NAME, cluster_name) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName) .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) .getSingleResult(); @@ -604,27 +612,29 @@ public List loadPerformanceProfileByName(String p @Override public List getKruizeResultsEntry(String experiment_name, String cluster_name, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { List kruizeResultsEntryList = new ArrayList<>(); + String clusterCondtionSql = ""; + if (cluster_name != null) + clusterCondtionSql = String.format(" and k.%s = :%s ", KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.CLUSTER_NAME); + else + clusterCondtionSql = String.format(" and k.%s is null ", KruizeConstants.JSONKeys.CLUSTER_NAME); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { - + Query kruizeResultsEntryQuery = null; 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.CLUSTER_NAME, cluster_name) + kruizeResultsEntryQuery = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_START_END_TIME + clusterCondtionSql, 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(); + .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time); } else if (interval_end_time != null) { - kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME, KruizeResultsEntry.class) - .setParameter(KruizeConstants.JSONKeys.CLUSTER_NAME, cluster_name) + kruizeResultsEntryQuery = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_END_TIME + clusterCondtionSql, KruizeResultsEntry.class) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name) - .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) - .getResultList(); + .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time); } else { - kruizeResultsEntryList = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_MAX_END_TIME, KruizeResultsEntry.class) - .setParameter(KruizeConstants.JSONKeys.CLUSTER_NAME, cluster_name) - .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name) - .getResultList(); + kruizeResultsEntryQuery = session.createQuery(SELECT_FROM_RESULTS_BY_EXP_NAME_AND_MAX_END_TIME + clusterCondtionSql, KruizeResultsEntry.class) + .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experiment_name); } + if (cluster_name != null) + kruizeResultsEntryQuery.setParameter(CLUSTER_NAME, cluster_name); + kruizeResultsEntryList = kruizeResultsEntryQuery.getResultList(); } catch (NoResultException e) { LOGGER.error(DBConstants.DB_MESSAGES.DATA_NOT_FOUND_KRUIZE_RESULTS, experiment_name, interval_end_time); kruizeResultsEntryList = null; diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index c1c84ac3f..1b5f43d8d 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -9,20 +9,24 @@ public static final class SQLQUERY { public static final String SELECT_FROM_EXPERIMENTS_BY_EXP_NAME = "from KruizeExperimentEntry k WHERE k.experiment_name = :experimentName"; 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_AND_LIMIT = String.format("from KruizeResultsEntry k " + - "WHERE k.cluster_name = :%s and k.experiment_name = :%s and" + - " k.interval_end_time <= :%s ORDER BY k.interval_end_time DESC", - KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); - public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT = String.format("from KruizeResultsEntry k " + - "WHERE k.cluster_name = :%s and k.experiment_name = :%s and k.interval_end_time <= :%s " + - "ORDER BY k.interval_end_time DESC", - KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); + public static final String SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT = + 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_START_END_TIME = String.format("from KruizeResultsEntry k " + - "WHERE k.cluster_name = :%s and k.experiment_name = :%s and k.interval_start_time >= :%s and " + - "k.interval_end_time <= :%s", - KruizeConstants.JSONKeys.CLUSTER_NAME, 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.cluster_name = :%s and k.experiment_name = :%s and k.interval_end_time = :%s", KruizeConstants.JSONKeys.CLUSTER_NAME, 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.cluster_name = :%s and 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.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME); + "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 = String.format("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.cluster_name= :%s and k.experiment_name = :%s and k.interval_end_time= :%s", KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); public static final String SELECT_FROM_RECOMMENDATIONS = "from KruizeRecommendationEntry"; From 5e988a4cbc04ac60299005838403209114b83dc4 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 26 Sep 2023 16:50:14 +0530 Subject: [PATCH 19/36] fixed when cluster_name is null while 2nd updateRecommendation called Signed-off-by: msvinaykumar --- .../database/dao/ExperimentDAOImpl.java | 17 ++++++++++++----- .../autotune/database/helper/DBConstants.java | 6 +++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index b0cc5f08e..bf4d41b43 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -565,16 +565,23 @@ public List loadRecommendationsByExperimentName(Strin public KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, String cluster_name, Timestamp interval_end_time) throws Exception { KruizeRecommendationEntry recommendationEntries = null; String statusValue = "failure"; + String clusterCondtionSql = ""; + if (cluster_name != null) + clusterCondtionSql = String.format(" and k.%s = :%s ", KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.CLUSTER_NAME); + else + clusterCondtionSql = String.format(" and k.%s is null ", KruizeConstants.JSONKeys.CLUSTER_NAME); + Timer.Sample timerLoadRecExpNameDate = Timer.start(MetricsConfig.meterRegistry()); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { - recommendationEntries = session.createQuery(SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME_AND_END_TIME, KruizeRecommendationEntry.class) - .setParameter(CLUSTER_NAME, cluster_name) + Query kruizeRecommendationEntryQuery = session.createQuery(SELECT_FROM_RECOMMENDATIONS_BY_EXP_NAME_AND_END_TIME + clusterCondtionSql, KruizeRecommendationEntry.class) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName) - .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time) - .getSingleResult(); + .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time); + if (cluster_name != null) + kruizeRecommendationEntryQuery.setParameter(CLUSTER_NAME, cluster_name); + recommendationEntries = kruizeRecommendationEntryQuery.getSingleResult(); statusValue = "success"; } catch (NoResultException e) { - LOGGER.debug("Generating mew recommendation for Experiment name : %s interval_end_time: %S", experimentName, interval_end_time); + LOGGER.debug("Generating new recommendation for Experiment name : %s interval_end_time: %S", experimentName, interval_end_time); } catch (Exception e) { LOGGER.error("Not able to load recommendations due to {}", e.getMessage()); recommendationEntries = null; diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index 1b5f43d8d..f116a9023 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -28,7 +28,11 @@ public static final class SQLQUERY { "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 = String.format("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.cluster_name= :%s and k.experiment_name = :%s and k.interval_end_time= :%s", KruizeConstants.JSONKeys.CLUSTER_NAME, KruizeConstants.JSONKeys.EXPERIMENT_NAME, KruizeConstants.JSONKeys.INTERVAL_END_TIME); + 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_PERFORMANCE_PROFILE = "from KruizePerformanceProfileEntry"; public static final String SELECT_FROM_PERFORMANCE_PROFILE_BY_NAME = "from KruizePerformanceProfileEntry k WHERE k.name = :name"; From 2056be8fb598cce38efd14e87a5d754e4710aed8 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Tue, 26 Sep 2023 19:12:05 +0530 Subject: [PATCH 20/36] fixed when cluster_name is null while 2nd updateRecommendation called Signed-off-by: msvinaykumar --- src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index bf4d41b43..5e10577e8 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -177,7 +177,7 @@ public List addToDBAndFetchFailedResults(List Date: Wed, 27 Sep 2023 21:03:07 +0530 Subject: [PATCH 21/36] optimal sql Signed-off-by: msvinaykumar --- .../ResourceOptimizationOpenshiftImpl.java | 45 +++++++------------ .../autotune/database/dao/ExperimentDAO.java | 2 +- .../database/dao/ExperimentDAOImpl.java | 13 +++--- .../autotune/database/helper/DBConstants.java | 8 +++- .../database/service/ExperimentDBService.java | 4 +- .../com/autotune/utils/KruizeConstants.java | 2 +- 6 files changed, 33 insertions(+), 41 deletions(-) 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 a4a2fb3e0..57ddcd8be 100644 --- a/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java +++ b/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java @@ -34,10 +34,7 @@ import org.slf4j.LoggerFactory; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Util class to validate the performance profile metrics with the experiment results metrics. @@ -83,36 +80,26 @@ public List getEngines() { @Override public void generateRecommendation(KruizeObject kruizeObject, List experimentResultDataList, Timestamp interval_start_time, Timestamp interval_end_time) throws Exception { /* - 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 + The general strategy involves initially attempting the optimal query; */ - String experiment_name = kruizeObject.getExperimentName(); - int theoriticalLimitRows = (int) (( - KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS * - KruizeConstants.DateFormats.MINUTES_FOR_DAY) - / kruizeObject.getTrial_settings().getMeasurement_durationMinutes_inDouble()); - - // Adding a 10% of value to make sure there are enough data points to gather the duration required - // Will be deprecated once we extract exact number of rows from DB based on duration in minutes needed for each term - int practicalLimitRows = RecommendationUtils.getThreshold(theoriticalLimitRows, 10, true); - - if (null != interval_start_time) { - long diffMilliseconds = interval_end_time.getTime() - interval_start_time.getTime(); - long minutes = diffMilliseconds / (60 * 1000); - int addToLimitRows = (int) (minutes / kruizeObject.getTrial_settings().getMeasurement_durationMinutes_inDouble()); - LOGGER.debug("add to limit rows set to {}", addToLimitRows); - practicalLimitRows = practicalLimitRows + addToLimitRows; - } - LOGGER.debug("Limit rows set to {}", practicalLimitRows); - - + // Convert the Timestamp to a Calendar instance in UTC time zone + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.setTimeInMillis(interval_end_time.getTime()); + /* + * interval_start_time Subtract (LONG_TERM_DURATION_DAYS + THRESHOLD days) + * Incorporate a buffer period of "threshold days" to account for potential remote cluster downtime. + * This adjustment aims to align the cumulative hours' duration with LONG_TERM_DURATION_DAYS. + */ + cal.add(Calendar.DAY_OF_MONTH, -(KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS + + KruizeConstants.RecommendationEngineConstants.DurationBasedEngine.DurationAmount.LONG_TERM_DURATION_DAYS_THRESHOLD)); + // Get the new Timestamp after subtracting 10 days + interval_start_time = new Timestamp(cal.getTimeInMillis()); Map mainKruizeExperimentMap = new HashMap<>(); + String experiment_name = kruizeObject.getExperimentName(); mainKruizeExperimentMap.put(experiment_name, kruizeObject); new ExperimentDBService().loadResultsFromDBByName(mainKruizeExperimentMap, experiment_name, - interval_end_time, - practicalLimitRows); + interval_start_time,interval_end_time); //TODO: Will be updated once algo is completed for (ExperimentResultData experimentResultData : experimentResultDataList) { if (null != kruizeObject && null != experimentResultData) { diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAO.java b/src/main/java/com/autotune/database/dao/ExperimentDAO.java index 9c60d84ce..4472c6147 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAO.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAO.java @@ -50,7 +50,7 @@ public interface ExperimentDAO { // Load all results for a particular experimentName - List loadResultsByExperimentName(String experimentName, String cluster_name, Timestamp interval_start_time, Integer limitRows) throws Exception; + List loadResultsByExperimentName(String experimentName, String cluster_name, 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/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index 5e10577e8..fe72b4bcd 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -502,7 +502,7 @@ public List loadExperimentByName(String experimentName) t } @Override - public List loadResultsByExperimentName(String experimentName, String cluster_name, Timestamp interval_end_time, Integer limitRows) throws Exception { + public List loadResultsByExperimentName(String experimentName, String cluster_name, Timestamp interval_start_time,Timestamp interval_end_time) throws Exception { // TODO: load only experimentStatus=inProgress , playback may not require completed experiments List kruizeResultsEntries = null; String statusValue = "failure"; @@ -512,16 +512,17 @@ public List loadResultsByExperimentName(String experimentNam else clusterCondtionSql = String.format(" and k.%s is null ", KruizeConstants.JSONKeys.CLUSTER_NAME); Timer.Sample timerLoadResultsExpName = Timer.start(MetricsConfig.meterRegistry()); + LOGGER.debug("startTime : {} , endTime : {}",interval_start_time,interval_end_time); + LOGGER.debug(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT + clusterCondtionSql); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { - if (null != limitRows && null != interval_end_time) { - Query kruizeResultsEntryQuery = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT + clusterCondtionSql + " ORDER BY k.interval_end_time DESC ", KruizeResultsEntry.class) + if (null != interval_start_time && null != interval_end_time) { + Query kruizeResultsEntryQuery = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT + clusterCondtionSql , KruizeResultsEntry.class) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName) + .setParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME, interval_start_time) .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time); if (cluster_name != null) kruizeResultsEntryQuery.setParameter(CLUSTER_NAME, cluster_name); - kruizeResultsEntries = kruizeResultsEntryQuery - .setMaxResults(limitRows) - .list(); + kruizeResultsEntries = kruizeResultsEntryQuery.list(); statusValue = "success"; } else { kruizeResultsEntries = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME, KruizeResultsEntry.class) diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index f116a9023..760412726 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -11,8 +11,12 @@ public static final class SQLQUERY { 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_AND_LIMIT = 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); + "WHERE k.experiment_name = :%s and " + + "k.interval_end_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_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 ", diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 7148ec771..63791c793 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -142,11 +142,11 @@ public void loadAllPerformanceProfiles(Map performan } } - public void loadResultsFromDBByName(Map mainKruizeExperimentMap, String experimentName, Timestamp interval_end_time, Integer limitRows) throws Exception { + public void loadResultsFromDBByName(Map mainKruizeExperimentMap, String experimentName, Timestamp interval_start_time,Timestamp interval_end_time) throws Exception { ExperimentInterface experimentInterface = new ExperimentInterfaceImpl(); KruizeObject kruizeObject = mainKruizeExperimentMap.get(experimentName); // Load results from the DB and save to local - List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, kruizeObject.getClusterName(), interval_end_time, limitRows); + List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, kruizeObject.getClusterName(), interval_start_time , interval_end_time); if (null != kruizeResultsEntries && !kruizeResultsEntries.isEmpty()) { List updateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(kruizeResultsEntries); if (null != updateResultsAPIObjects && !updateResultsAPIObjects.isEmpty()) { diff --git a/src/main/java/com/autotune/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java index 8e4012cf2..fd0f0b1d2 100644 --- a/src/main/java/com/autotune/utils/KruizeConstants.java +++ b/src/main/java/com/autotune/utils/KruizeConstants.java @@ -442,7 +442,7 @@ public static final class DurationAmount { public static final int SHORT_TERM_DURATION_DAYS = 1; public static final int MEDIUM_TERM_DURATION_DAYS = 7; public static final int LONG_TERM_DURATION_DAYS = 15; - + public static final int LONG_TERM_DURATION_DAYS_THRESHOLD = 2; private DurationAmount() { } From 4933084f64caff2ef78862433c96dc9908d745bd Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 28 Sep 2023 14:20:00 +0530 Subject: [PATCH 22/36] incorporated as per review comment Signed-off-by: msvinaykumar --- .../ResourceOptimizationOpenshiftImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 57ddcd8be..a76e3e4f2 100644 --- a/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java +++ b/src/main/java/com/autotune/analyzer/performanceProfiles/PerformanceProfileInterface/ResourceOptimizationOpenshiftImpl.java @@ -93,13 +93,13 @@ public void generateRecommendation(KruizeObject kruizeObject, List mainKruizeExperimentMap = new HashMap<>(); String experiment_name = kruizeObject.getExperimentName(); mainKruizeExperimentMap.put(experiment_name, kruizeObject); new ExperimentDBService().loadResultsFromDBByName(mainKruizeExperimentMap, experiment_name, - interval_start_time,interval_end_time); + calculated_start_time,interval_end_time); //TODO: Will be updated once algo is completed for (ExperimentResultData experimentResultData : experimentResultDataList) { if (null != kruizeObject && null != experimentResultData) { From 30a2671e064bb6c06202a1aa6034739cccffcb25 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 28 Sep 2023 16:11:58 +0530 Subject: [PATCH 23/36] incorporated review comments Signed-off-by: msvinaykumar --- .../minikube/kruize-crc-minikube.yaml | 3 ++- .../com/autotune/database/dao/ExperimentDAOImpl.java | 9 ++++----- .../java/com/autotune/database/helper/DBConstants.java | 2 +- .../autotune/database/service/ExperimentDBService.java | 4 ++-- src/main/java/com/autotune/utils/KruizeConstants.java | 2 ++ 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index c4b6f0575..dfb402b2c 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -199,6 +199,7 @@ apiVersion: batch/v1 kind: CronJob metadata: name: create-partition-cronjob + namespace: monitoring spec: schedule: "0 0 25 * *" # Run on 25th of every month at midnight jobTemplate: @@ -216,7 +217,7 @@ spec: - sh - -c - | - chmod +x /home/autotune/app/target/bin/CreatePartition && /home/autotune/app/target/bin/CreatePartition + /home/autotune/app/target/bin/CreatePartition args: [ "" ] env: - name: START_AUTOTUNE diff --git a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java index fe72b4bcd..b1c8d9d37 100644 --- a/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java +++ b/src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java @@ -502,7 +502,7 @@ public List loadExperimentByName(String experimentName) t } @Override - public List loadResultsByExperimentName(String experimentName, String cluster_name, Timestamp interval_start_time,Timestamp interval_end_time) throws Exception { + public List loadResultsByExperimentName(String experimentName, String cluster_name, Timestamp calculated_start_time,Timestamp interval_end_time) throws Exception { // TODO: load only experimentStatus=inProgress , playback may not require completed experiments List kruizeResultsEntries = null; String statusValue = "failure"; @@ -512,13 +512,12 @@ public List loadResultsByExperimentName(String experimentNam else clusterCondtionSql = String.format(" and k.%s is null ", KruizeConstants.JSONKeys.CLUSTER_NAME); Timer.Sample timerLoadResultsExpName = Timer.start(MetricsConfig.meterRegistry()); - LOGGER.debug("startTime : {} , endTime : {}",interval_start_time,interval_end_time); - LOGGER.debug(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT + clusterCondtionSql); + LOGGER.debug("startTime : {} , endTime : {}",calculated_start_time,interval_end_time); try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) { - if (null != interval_start_time && null != interval_end_time) { + if (null != calculated_start_time && null != interval_end_time) { Query kruizeResultsEntryQuery = session.createQuery(DBConstants.SQLQUERY.SELECT_FROM_RESULTS_BY_EXP_NAME_AND_DATE_RANGE_AND_LIMIT + clusterCondtionSql , KruizeResultsEntry.class) .setParameter(KruizeConstants.JSONKeys.EXPERIMENT_NAME, experimentName) - .setParameter(KruizeConstants.JSONKeys.INTERVAL_START_TIME, interval_start_time) + .setParameter(KruizeConstants.JSONKeys.CALCULATED_START_TIME, calculated_start_time) .setParameter(KruizeConstants.JSONKeys.INTERVAL_END_TIME, interval_end_time); if (cluster_name != null) kruizeResultsEntryQuery.setParameter(CLUSTER_NAME, cluster_name); diff --git a/src/main/java/com/autotune/database/helper/DBConstants.java b/src/main/java/com/autotune/database/helper/DBConstants.java index 760412726..0e9f8cfc5 100644 --- a/src/main/java/com/autotune/database/helper/DBConstants.java +++ b/src/main/java/com/autotune/database/helper/DBConstants.java @@ -15,7 +15,7 @@ public static final class SQLQUERY { "k.interval_end_time >= :%s and " + "k.interval_end_time <= :%s ", KruizeConstants.JSONKeys.EXPERIMENT_NAME, - KruizeConstants.JSONKeys.INTERVAL_START_TIME, + KruizeConstants.JSONKeys.CALCULATED_START_TIME, KruizeConstants.JSONKeys.INTERVAL_END_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 " + diff --git a/src/main/java/com/autotune/database/service/ExperimentDBService.java b/src/main/java/com/autotune/database/service/ExperimentDBService.java index 63791c793..1e7318052 100644 --- a/src/main/java/com/autotune/database/service/ExperimentDBService.java +++ b/src/main/java/com/autotune/database/service/ExperimentDBService.java @@ -142,11 +142,11 @@ public void loadAllPerformanceProfiles(Map performan } } - public void loadResultsFromDBByName(Map mainKruizeExperimentMap, String experimentName, Timestamp interval_start_time,Timestamp interval_end_time) throws Exception { + public void loadResultsFromDBByName(Map mainKruizeExperimentMap, String experimentName, Timestamp calculated_start_time,Timestamp interval_end_time) throws Exception { ExperimentInterface experimentInterface = new ExperimentInterfaceImpl(); KruizeObject kruizeObject = mainKruizeExperimentMap.get(experimentName); // Load results from the DB and save to local - List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, kruizeObject.getClusterName(), interval_start_time , interval_end_time); + List kruizeResultsEntries = experimentDAO.loadResultsByExperimentName(experimentName, kruizeObject.getClusterName(), calculated_start_time , interval_end_time); if (null != kruizeResultsEntries && !kruizeResultsEntries.isEmpty()) { List updateResultsAPIObjects = DBHelpers.Converters.KruizeObjectConverters.convertResultEntryToUpdateResultsAPIObject(kruizeResultsEntries); if (null != updateResultsAPIObjects && !updateResultsAPIObjects.isEmpty()) { diff --git a/src/main/java/com/autotune/utils/KruizeConstants.java b/src/main/java/com/autotune/utils/KruizeConstants.java index fd0f0b1d2..f11ea8675 100644 --- a/src/main/java/com/autotune/utils/KruizeConstants.java +++ b/src/main/java/com/autotune/utils/KruizeConstants.java @@ -187,6 +187,8 @@ public static final class JSONKeys { public static final String CONTAINER_IMAGE_NAME = "container_image_name"; public static final String RECOMMENDATION_SETTINGS = "recommendation_settings"; public static final String INTERVAL_START_TIME = "interval_start_time"; + + public static final String CALCULATED_START_TIME = "calculated_start_time"; public static final String INTERVAL_END_TIME = "interval_end_time"; public static final String DURATION_IN_MINUTES = "duration_in_minutes"; public static final String DURATION_IN_HOURS = "duration_in_hours"; From 103a3587384069f536cf869f48fe8493f1e16f36 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 28 Sep 2023 19:53:16 +0530 Subject: [PATCH 24/36] added execute permission Signed-off-by: msvinaykumar --- Dockerfile.autotune | 3 +++ .../minikube/kruize-crc-minikube.yaml | 3 ++- .../openshift/kruize-crc-openshift.yaml | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Dockerfile.autotune b/Dockerfile.autotune index 4eb6020de..5ac08b72f 100644 --- a/Dockerfile.autotune +++ b/Dockerfile.autotune @@ -89,6 +89,9 @@ COPY --chown=${UID}:0 --from=mvnbuild-jdk17 ${AUTOTUNE_HOME}/src/autotune/jre/ $ # Copy the app binaries COPY --chown=${UID}:0 --from=mvnbuild-jdk17 ${AUTOTUNE_HOME}/src/autotune/target/ ${AUTOTUNE_HOME}/app/target/ +# Grant execute permission +RUN chmod +x $AUTOTUNE_HOME/app/target/bin/CreatePartition + EXPOSE 8080 ENV JAVA_HOME=${AUTOTUNE_HOME}/app/jre \ diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index c4b6f0575..4296599c2 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -199,6 +199,7 @@ apiVersion: batch/v1 kind: CronJob metadata: name: create-partition-cronjob + namespace: openshift-tuning spec: schedule: "0 0 25 * *" # Run on 25th of every month at midnight jobTemplate: @@ -216,7 +217,7 @@ spec: - sh - -c - | - chmod +x /home/autotune/app/target/bin/CreatePartition && /home/autotune/app/target/bin/CreatePartition + /home/autotune/app/target/bin/CreatePartition args: [ "" ] env: - name: START_AUTOTUNE diff --git a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml index c93640073..9301ef43f 100644 --- a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml @@ -252,6 +252,7 @@ apiVersion: batch/v1 kind: CronJob metadata: name: create-partition-cronjob + namespace: openshift-tuning spec: schedule: "0 0 25 * *" # Run on 25th of every month at midnight jobTemplate: @@ -269,7 +270,7 @@ spec: - sh - -c - | - chmod +x /home/autotune/app/target/bin/CreatePartition && /home/autotune/app/target/bin/CreatePartition + /home/autotune/app/target/bin/CreatePartition args: [ "" ] env: - name: START_AUTOTUNE From a4fa839ec59cdd857b54139b8ee81b981efb808a Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 29 Sep 2023 11:47:43 +0530 Subject: [PATCH 25/36] incorporated review comment Signed-off-by: msvinaykumar --- Dockerfile.autotune | 2 +- .../minikube/kruize-crc-minikube.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile.autotune b/Dockerfile.autotune index 5ac08b72f..266a642bb 100644 --- a/Dockerfile.autotune +++ b/Dockerfile.autotune @@ -90,7 +90,7 @@ COPY --chown=${UID}:0 --from=mvnbuild-jdk17 ${AUTOTUNE_HOME}/src/autotune/jre/ $ COPY --chown=${UID}:0 --from=mvnbuild-jdk17 ${AUTOTUNE_HOME}/src/autotune/target/ ${AUTOTUNE_HOME}/app/target/ # Grant execute permission -RUN chmod +x $AUTOTUNE_HOME/app/target/bin/CreatePartition +RUN chmod -R +x $AUTOTUNE_HOME/app/target EXPOSE 8080 diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index 4296599c2..dfb402b2c 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -199,7 +199,7 @@ apiVersion: batch/v1 kind: CronJob metadata: name: create-partition-cronjob - namespace: openshift-tuning + namespace: monitoring spec: schedule: "0 0 25 * *" # Run on 25th of every month at midnight jobTemplate: From 5731c5ee7006eb6ea149c984f6d8c300438370bc Mon Sep 17 00:00:00 2001 From: bharathappali Date: Thu, 28 Sep 2023 14:59:33 +0530 Subject: [PATCH 26/36] Add threshold time to calculate the recommendations Signed-off-by: bharathappali --- .../RecommendationConstants.java | 4 ++ .../DurationBasedRecommendationEngine.java | 57 ++++++++++++++++--- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/autotune/analyzer/recommendations/RecommendationConstants.java b/src/main/java/com/autotune/analyzer/recommendations/RecommendationConstants.java index c88207316..262102978 100644 --- a/src/main/java/com/autotune/analyzer/recommendations/RecommendationConstants.java +++ b/src/main/java/com/autotune/analyzer/recommendations/RecommendationConstants.java @@ -654,6 +654,10 @@ public static final class RecommendationValueConstants { public static final Double MEM_SPIKE_BUFFER_DECIMAL = 0.05; public static final Double DEFAULT_CPU_THRESHOLD = 0.1; public static final Double DEFAULT_MEMORY_THRESHOLD = 0.1; + + public static final int THRESHOLD_HRS_SHORT_TERM = 6; + public static final int THRESHOLD_HRS_MEDIUM_TERM = 6; + public static final int THRESHOLD_HRS_LONG_TERM = 6; } public static final class RecommendationNotificationMsgConstant { diff --git a/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java b/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java index 9a21fe98b..81cc8c567 100644 --- a/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java +++ b/src/main/java/com/autotune/analyzer/recommendations/engine/DurationBasedRecommendationEngine.java @@ -34,6 +34,7 @@ import java.sql.Timestamp; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static com.autotune.analyzer.recommendations.RecommendationConstants.RecommendationValueConstants.*; @@ -66,16 +67,20 @@ private static Timestamp getMonitoringStartTime(HashMap= durationBasedRecommendationSubCategory.getGetDurationLowerBound()) { - // Storing the timestamp value in startTimestamp variable to return - intervalEndTime = timestamp; - break; - } + if (timestamp.before(thresholdTime)) { + // Breaking condition not met so we can be sure that data is not sufficient hence return null + return null; } + sum = sum + sortedResultsHashMap.get(timestamp).getDurationInMinutes(); + if (sum >= durationBasedRecommendationSubCategory.getGetDurationLowerBound()) { + // Storing the timestamp value in startTimestamp variable to return + intervalEndTime = timestamp; + break; + } + } } try { @@ -1116,4 +1121,42 @@ public boolean checkIfMinDataAvailable(ContainerData containerData) { } return false; } + + private static Timestamp calculateThresholdTimeBasedOnTerm(DurationBasedRecommendationSubCategory durationBasedRecommendationSubCategory, Timestamp endTime) { + // Check for null + if (null == durationBasedRecommendationSubCategory || null == endTime) + return null; + // Initialise threshold time + Timestamp thresholdTime = null; + + // Extract the duration as count + int count = durationBasedRecommendationSubCategory.getDuration(); + // Extract units + TimeUnit units = durationBasedRecommendationSubCategory.getRecommendationDurationUnits(); + + // Assuming units is hours by default + int totalDurationInHrs = count; + + // Checking if it's days + if (units == TimeUnit.DAYS) { + totalDurationInHrs = count * KruizeConstants.TimeConv.NO_OF_HOURS_PER_DAY; + } + // TODO: Add checks for other timeunits like minutes, weeks & months if needed later + + // Add Threshold based on term + if (durationBasedRecommendationSubCategory.getSubCategory().equalsIgnoreCase(KruizeConstants.JSONKeys.SHORT_TERM)) + totalDurationInHrs = totalDurationInHrs + THRESHOLD_HRS_SHORT_TERM; + else if (durationBasedRecommendationSubCategory.getSubCategory().equalsIgnoreCase(KruizeConstants.JSONKeys.MEDIUM_TERM)) + totalDurationInHrs = totalDurationInHrs + THRESHOLD_HRS_MEDIUM_TERM; + else if (durationBasedRecommendationSubCategory.getSubCategory().equalsIgnoreCase(KruizeConstants.JSONKeys.LONG_TERM)) + totalDurationInHrs = totalDurationInHrs + THRESHOLD_HRS_LONG_TERM; + + // Remove the number of hours from end time + long endTimeMillis = endTime.getTime(); + long startTimeMillis = endTimeMillis - TimeUnit.HOURS.toMillis(totalDurationInHrs); + + thresholdTime = new Timestamp(startTimeMillis); + + return thresholdTime; + } } From 065408d9a57e7eca2115a7aa2c0fccd9f07055cd Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Fri, 29 Sep 2023 12:04:15 +0530 Subject: [PATCH 27/36] incorporated review comment Signed-off-by: msvinaykumar --- Dockerfile.autotune | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.autotune b/Dockerfile.autotune index 266a642bb..4cb7f414f 100644 --- a/Dockerfile.autotune +++ b/Dockerfile.autotune @@ -90,7 +90,7 @@ COPY --chown=${UID}:0 --from=mvnbuild-jdk17 ${AUTOTUNE_HOME}/src/autotune/jre/ $ COPY --chown=${UID}:0 --from=mvnbuild-jdk17 ${AUTOTUNE_HOME}/src/autotune/target/ ${AUTOTUNE_HOME}/app/target/ # Grant execute permission -RUN chmod -R +x $AUTOTUNE_HOME/app/target +RUN chmod -R +x $AUTOTUNE_HOME/app/target/bin/ EXPOSE 8080 From a4c28da148d99516221b033e8bcd01134f92f27f Mon Sep 17 00:00:00 2001 From: Dinakar Guniguntala Date: Fri, 29 Sep 2023 12:12:46 +0530 Subject: [PATCH 28/36] Bump remote_monitoring to 0.0.19.2_rm Signed-off-by: Dinakar Guniguntala --- .../crc/BYODB-installation/minikube/kruize-crc-minikube.yaml | 4 ++-- .../BYODB-installation/openshift/kruize-crc-openshift.yaml | 4 ++-- .../minikube/kruize-crc-minikube.yaml | 2 +- .../openshift/kruize-crc-openshift.yaml | 2 +- pom.xml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml index d57c20b38..a3c858a58 100644 --- a/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/BYODB-installation/minikube/kruize-crc-minikube.yaml @@ -65,7 +65,7 @@ spec: spec: containers: - name: kruize - image: kruize/autotune_operator:0.0.19_rm + image: kruize/autotune_operator:0.0.19.2_rm imagePullPolicy: Always volumeMounts: - name: config-volume @@ -188,7 +188,7 @@ metadata: spec: containers: - name: kruize-ui-nginx-container - image: quay.io/kruize/kruize-ui:0.0.1 + image: quay.io/kruize/kruize-ui:0.0.2 imagePullPolicy: Always env: - name: KRUIZE_UI_ENV diff --git a/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml index 5d5b8f64a..ff1b8a8e0 100644 --- a/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/BYODB-installation/openshift/kruize-crc-openshift.yaml @@ -65,7 +65,7 @@ spec: spec: containers: - name: kruize - image: kruize/autotune_operator:0.0.19_rm + image: kruize/autotune_operator:0.0.19.2_rm imagePullPolicy: Always volumeMounts: - name: config-volume @@ -194,7 +194,7 @@ metadata: spec: containers: - name: kruize-ui-nginx-container - image: quay.io/kruize/kruize-ui:0.0.1 + image: quay.io/kruize/kruize-ui:0.0.2 imagePullPolicy: Always env: - name: KRUIZE_UI_ENV diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index dfb402b2c..6a493d21f 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -143,7 +143,7 @@ spec: spec: containers: - name: kruize - image: kruize/autotune_operator:0.0.19_rm + image: kruize/autotune_operator:0.0.19.2_rm imagePullPolicy: Always volumeMounts: - name: config-volume diff --git a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml index 9301ef43f..72facaf6d 100644 --- a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml @@ -189,7 +189,7 @@ spec: serviceAccountName: kruize-sa containers: - name: kruize - image: kruize/autotune_operator:0.0.19_rm + image: kruize/autotune_operator:0.0.19.2_rm imagePullPolicy: Always volumeMounts: - name: config-volume diff --git a/pom.xml b/pom.xml index 5376d9d90..6a10f3db3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.autotune autotune - 0.0.19_mvp + 0.0.19.2_mvp 4.13.0 20201115 From 9a5baa925d39110d7cbedcfd357e3dbd0378532e Mon Sep 17 00:00:00 2001 From: bharathappali Date: Fri, 29 Sep 2023 13:21:49 +0530 Subject: [PATCH 29/36] Add sample expandable step in doc Signed-off-by: bharathappali --- design/MonitoringModeAPI.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index 92e4cf05a..e4c0cb0b7 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -16,7 +16,13 @@ see [Create Experiment](/design/CreateExperiment.md) `curl -H 'Accept: application/json' -X POST --data 'copy paste below JSON' http://:/createExperiment` -``` +
+ +Example Request + +### Example Request + +```json [ { "version": "1.0", @@ -51,10 +57,17 @@ see [Create Experiment](/design/CreateExperiment.md) } ] ``` +
+ **Response** -``` +
+Example Response + +### Example Response + +```json { "message": "Experiment registered successfully with Autotune. View registered experiments at /listExperiments", "httpcode": 201, @@ -62,6 +75,8 @@ see [Create Experiment](/design/CreateExperiment.md) "status": "SUCCESS" } ``` +
+ ## Update Metric Results From 920bf1ac1b897cc250a2e53faa34905cfa2fe282 Mon Sep 17 00:00:00 2001 From: bharathappali Date: Fri, 29 Sep 2023 14:58:08 +0530 Subject: [PATCH 30/36] add expandable sections for all JSONS Signed-off-by: bharathappali --- design/MonitoringModeAPI.md | 183 +++++++++++++++++++++++++++++++----- 1 file changed, 157 insertions(+), 26 deletions(-) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index e4c0cb0b7..6566e2d63 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -97,7 +97,12 @@ see [Update results](/design/UpdateResults.md) `curl -H 'Accept: application/json' -X POST --data 'copy paste below JSON' http://:/updateResults` -``` +
+Example Request + +### Example Request + +```json [ { "version": "1.0", @@ -329,12 +334,17 @@ see [Update results](/design/UpdateResults.md) ] } ] - ``` +
**Response** -``` +
+Example Response + +### Example Response + +```json { "message": "Updated metrics results successfully with Autotune. View update results at /listExperiments", "httpcode": 201, @@ -342,6 +352,8 @@ see [Update results](/design/UpdateResults.md) "status": "SUCCESS" } ``` +
+ The UpdateResults API has been enhanced to support bulk uploads of up to 100 records at once. When all records are successfully processed, the API will return the same success response as depicted above. However, if any or all of the @@ -350,7 +362,12 @@ structure outlined below for handling duplicate records: **Response** -``` +
+Example Response + +### Example Response + +```json { "message": "Out of a total of 3 records, 3 failed to save", "httpcode": 400, @@ -400,6 +417,8 @@ structure outlined below for handling duplicate records: ] } ``` +
+ **Response** @@ -407,7 +426,12 @@ In the response below, among the three records, one record was successfully save The failed records are indicated in the 'data' attribute using the 'error' attribute, allowing you to identify the specific attribute causing the failures. -``` +
+Example Response + +### Example Response + +```json { "message": "Out of a total of 3 records, 2 failed to save", "httpcode": 400, @@ -445,6 +469,9 @@ specific attribute causing the failures. ] } ``` +
+ +## List Experiments **Request with experiment name parameter** @@ -466,7 +493,12 @@ Returns the latest result of all the experiments **Response for experiment name - `quarkus-resteasy-kruize-min-http-response-time-db_0`** -``` +
+Example Response + +### Example Response + +```json [ { "version": "1.0", @@ -649,6 +681,9 @@ Returns the latest result of all the experiments ] ``` +
+ +
**Request with results set to true and with experiment name parameter** @@ -670,7 +705,12 @@ Returns all the results of all the experiments **Response for experiment name - `quarkus-resteasy-kruize-min-http-response-time-db_0`** -``` +
+Example Response + +### Example Response + +```json [ { "version": "1.0", @@ -897,6 +937,9 @@ Returns all the results of all the experiments ] ``` +
+ +
**Request with results set to true, latest set to false and with experiment name parameter** @@ -917,7 +960,12 @@ Returns the latest recommendations of all the experiments **Response for experiment name - `quarkus-resteasy-kruize-min-http-response-time-db_0`** -``` +
+Example Response + +### Example Response + +```json [ { "version": "1.0", @@ -1156,6 +1204,9 @@ Returns the latest recommendations of all the experiments ] ``` +
+ +

**Request with recommendations set to true with experiment name parameter** @@ -1176,7 +1227,12 @@ Returns all the recommendations of all the experiments **Response for experiment name - `quarkus-resteasy-kruize-min-http-response-time-db_0`** -``` +
+Example Response + +### Example Response + +```json [ { "version": "1.0", @@ -1453,6 +1509,9 @@ Returns all the recommendations of all the experiments ] ``` +
+ +

**Request with recommendations set to true, latest set to false and with experiment name parameter** @@ -1487,7 +1546,7 @@ name parameter** Returns all the recommendations and all the results of the specified experiment. -## Recommendations +## List Recommendations List recommendations output JSON as follows. Some parameters like CPU limit , ENV are optional. @@ -1511,7 +1570,12 @@ If no parameter is passed API returns all the latest recommendations available f **Response** -``` +
+Example Response + +### Example Response + +```json [ { "cluster_name": "cluster-one-division-bell", @@ -1705,6 +1769,9 @@ If no parameter is passed API returns all the latest recommendations available f ] ``` +
+ + **Request with experiment name parameter** `GET /listRecommendations` @@ -1715,7 +1782,12 @@ Returns the latest result of that experiment **Response for experiment name - `quarkus-resteasy-kruize-min-http-response-time-db_0`** -``` +
+Example Response + +### Example Response + +```json [ { "cluster_name": "cluster-one-division-bell", @@ -1864,6 +1936,9 @@ Returns the latest result of that experiment ] ``` +
+ + **Request with experiment name parameter and latest set to false** `GET /listRecommendations` @@ -1874,7 +1949,12 @@ Returns all the results of that experiment **Response for experiment name - `quarkus-resteasy-kruize-min-http-response-time-db_0`** -``` +
+Example Response + +### Example Response + +```json [ { "cluster_name": "cluster-one-division-bell", @@ -2124,6 +2204,9 @@ Returns all the results of that experiment ] ``` +
+ + **Request with experiment name parameter and monitoring end time set to a valid timestamp** `GET /listRecommendations` @@ -2135,7 +2218,13 @@ Returns the recommendation at a particular timestamp if it exists **Response for experiment name - `quarkus-resteasy-kruize-min-http-response-time-db_0` and Monitoring End Time - `2022-12-20T17:55:05.000Z`** -``` + +
+Example Response + +### Example Response + +```json [ { "cluster_name": "cluster-one-division-bell", @@ -2270,13 +2359,17 @@ Time - `2022-12-20T17:55:05.000Z`** ] ``` +
+ + ### Invalid Scenarios: -**Invalid experiment name** +
+Invalid experiment name `experiment_name=stub-experiment` -``` +```json { "message": "Given experiment name - \" stub-experiment \" is not valid", "httpcode": 400, @@ -2284,12 +2377,14 @@ Time - `2022-12-20T17:55:05.000Z`** "status": "ERROR" } ``` +
-**Invalid Timestamp format** +
+Invalid Timestamp format `monitoring_end_time=Tony Stark` (Invalid Timestamp) -``` +```json { "message": "Given timestamp - \" Tony Stark \" is not a valid timestamp format", "httpcode": 400, @@ -2297,12 +2392,15 @@ Time - `2022-12-20T17:55:05.000Z`** "status": "ERROR" } ``` +
+ -**Non Existing Timestamp** +
+Non Existing Timestamp `monitoring_end_time=2022-12-20T17:55:07.000Z` -``` +```json { "message": "Recommendation for timestamp - \" 2022-12-20T17:55:07.000Z \" does not exist", "httpcode": 400, @@ -2310,6 +2408,10 @@ Time - `2022-12-20T17:55:05.000Z`** "status": "ERROR" } ``` +
+ + + ## Update Recommendations API @@ -2352,7 +2454,8 @@ success status code : 201 The response will contain a array of JSON object with the updated recommendations for the specified experiment. -Example Response Body: +
+Example Response Body ```json [ @@ -2466,6 +2569,10 @@ Example Response Body: ] ``` +
+ + + **Error Responses** | HTTP Status Code | Description | @@ -2491,7 +2598,12 @@ least three attempts for the following scenarios: If the API responds with "Profile Name not found," implement retry logic. -``` +
+Example Response + +### Example Response + +```json { "message": "Not Found: performance_profile does not exist: resource-optimization-openshift", "httpcode": 400, @@ -2500,6 +2612,8 @@ If the API responds with "Profile Name not found," implement retry logic. } ``` +
+ ```POST /updateResults``` If the API responds with: @@ -2509,7 +2623,12 @@ If the API responds with: Implement retry logic. -``` +
+Example Response + +### Example Response + +```json { "message": "Out of a total of 2 records, 1 failed to save", "httpcode": 400, @@ -2534,7 +2653,7 @@ Implement retry logic. } ``` -``` +```json { "message": "Out of a total of 2 records, 1 failed to save", "httpcode": 400, @@ -2559,6 +2678,10 @@ Implement retry logic. } ``` +
+ + + ```POST /updateRecommendations?interval_end_time=&experiment_name=``` If the API responds with: @@ -2568,7 +2691,12 @@ If the API responds with: Implement retry logic. -``` +
+Example Response + +### Example Response + +```json { "message": "Not Found: experiment_name does not exist: quarkus-resteasy-kruize-min-http-response-time-db_1_2", "httpcode": 400, @@ -2577,7 +2705,7 @@ Implement retry logic. } ``` -``` +```json { "message": "Not Found: interval_end_time does not exist: 2023-02-02T00:00:00.000Z", "httpcode": 400, @@ -2585,6 +2713,9 @@ Implement retry logic. "status": "ERROR" } ``` +
+ + ```POST /*``` From a9da74ab3c1d889ba14373b639007dfe81a49138 Mon Sep 17 00:00:00 2001 From: bharathappali Date: Fri, 29 Sep 2023 15:07:39 +0530 Subject: [PATCH 31/36] Add write up about terms and thresholds Signed-off-by: bharathappali --- design/MonitoringModeAPI.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index 6566e2d63..af243a523 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -6,6 +6,19 @@ Documentation still in progress stay tuned. **Note :** The ISO 8601 standard underpins all timestamp formats. An example of a valid timestamp in this format is 2022-01-23T18:25:43.511Z, which represents January 23, 2022, at 18:25:43.511 UTC. +### Resource Analysis Terms and Defaults + +When analyzing resource utilization in Kubernetes, it's essential to define terms that specify the duration of past data considered for recommendations and the threshold for obtaining additional data. These terms help in categorizing and fine-tuning resource allocation. + +Below are the default terms used in resource analysis, along with their respective durations and thresholds: + +| Term | Duration | Threshold | +|------------|----------|-----------| +| Short | 1 day | 6 hours | +| Medium | 7 days | 6 hours | +| Long | 15 days | 6 hours | + + ## CreateExperiment This is quick guide instructions to create experiments using input JSON as follows. For a more detailed guide, From 693686d83f8c796c709840a40990ecaa97c59f60 Mon Sep 17 00:00:00 2001 From: bharathappali Date: Fri, 29 Sep 2023 15:13:54 +0530 Subject: [PATCH 32/36] Add doc for thresholds and terms description Signed-off-by: bharathappali --- design/MonitoringModeAPI.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index af243a523..bebcbaa39 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -6,7 +6,7 @@ Documentation still in progress stay tuned. **Note :** The ISO 8601 standard underpins all timestamp formats. An example of a valid timestamp in this format is 2022-01-23T18:25:43.511Z, which represents January 23, 2022, at 18:25:43.511 UTC. -### Resource Analysis Terms and Defaults +## Resource Analysis Terms and Defaults When analyzing resource utilization in Kubernetes, it's essential to define terms that specify the duration of past data considered for recommendations and the threshold for obtaining additional data. These terms help in categorizing and fine-tuning resource allocation. @@ -18,6 +18,33 @@ Below are the default terms used in resource analysis, along with their respecti | Medium | 7 days | 6 hours | | Long | 15 days | 6 hours | +**Short Term** + + Duration: 24 hours + Threshold: 6 hours + +**Duration**: The "duration" in the short-term analysis refers to the amount of historical data taken into account when assessing resource utilization. In this case, it covers the most recent 24 hours of data. + +**Threshold**: The "threshold" is an additional buffer period. It encompasses the 24-hour duration and extends an extra six hours. This buffer accommodates any potential data gaps or misses within the 24-hour window, ensuring a comprehensive analysis. + +**Medium Term** + + Duration: 7 days + Threshold: 6 hours + +**Duration**: The "duration" for the medium-term analysis extends further into the past, considering resource data from the last seven days. It provides a broader perspective on resource trends and utilization. + +**Threshold**: Similar to the short term, the "threshold" for the medium term includes an extra buffer of six hours. This buffer complements the seven-day duration, accounting for any data discrepancies or gaps within that timeframe. + +**Long Term** + + Duration: 15 days + Threshold: 6 hours + +**Duration**: The "duration" in the long-term analysis offers insights into resource utilization over a more extended period, encompassing data from the last 15 days. This extended timeframe allows for a comprehensive evaluation of resource patterns. + +**Threshold**: Like the short and medium terms, the "threshold" for the long term includes a buffer period of six hours. This buffer enhances the 15-day duration, ensuring that any missing or delayed data is considered during the analysis. + ## CreateExperiment From 504b3ab3443da76f12fa482562c8cdf3c26d799e Mon Sep 17 00:00:00 2001 From: bharathappali Date: Fri, 29 Sep 2023 16:01:40 +0530 Subject: [PATCH 33/36] Add table of content Signed-off-by: bharathappali --- design/MonitoringModeAPI.md | 68 +++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index bebcbaa39..5f3308ecd 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -6,19 +6,59 @@ Documentation still in progress stay tuned. **Note :** The ISO 8601 standard underpins all timestamp formats. An example of a valid timestamp in this format is 2022-01-23T18:25:43.511Z, which represents January 23, 2022, at 18:25:43.511 UTC. +# Table of Contents + +1. [Resource Analysis Terms and Defaults](#resource-analysis-terms-and-defaults) + - [Terms, Duration & Threshold Table](#terms-duration--threshold-table) + - [Short Term](#short-term) + - [Medium Term](#medium-term) + - [Long Term](#long-term) + +2. [API's](#apis) + - [Create Experiment API](#create-experiment-api) + - Introduction + - Example Request and Response + - Invalid Scenarios + + - [Update Results API](#update-results-api) + - Introduction + - Example Request and Response + - Invalid Scenarios + + - [List Experiments API](#list-experiments-api) + - Introduction + - Example Request and Response + - Invalid Scenarios + + - [List Recommendations API](#list-recommendations-api) + - Introduction + - Example Request and Response + - Invalid Scenarios + + - [Update Recommendations API](#update-recommendations-api) + - Introduction + - Example Request and Response + - Invalid Scenarios + + + ## Resource Analysis Terms and Defaults When analyzing resource utilization in Kubernetes, it's essential to define terms that specify the duration of past data considered for recommendations and the threshold for obtaining additional data. These terms help in categorizing and fine-tuning resource allocation. Below are the default terms used in resource analysis, along with their respective durations and thresholds: + +### Terms, Duration & Threshold Table + | Term | Duration | Threshold | |------------|----------|-----------| | Short | 1 day | 6 hours | | Medium | 7 days | 6 hours | | Long | 15 days | 6 hours | -**Short Term** + +##### Short Term Duration: 24 hours Threshold: 6 hours @@ -27,7 +67,8 @@ Below are the default terms used in resource analysis, along with their respecti **Threshold**: The "threshold" is an additional buffer period. It encompasses the 24-hour duration and extends an extra six hours. This buffer accommodates any potential data gaps or misses within the 24-hour window, ensuring a comprehensive analysis. -**Medium Term** + +##### Medium Term Duration: 7 days Threshold: 6 hours @@ -36,7 +77,8 @@ Below are the default terms used in resource analysis, along with their respecti **Threshold**: Similar to the short term, the "threshold" for the medium term includes an extra buffer of six hours. This buffer complements the seven-day duration, accounting for any data discrepancies or gaps within that timeframe. -**Long Term** + +##### Long Term Duration: 15 days Threshold: 6 hours @@ -45,8 +87,12 @@ Below are the default terms used in resource analysis, along with their respecti **Threshold**: Like the short and medium terms, the "threshold" for the long term includes a buffer period of six hours. This buffer enhances the 15-day duration, ensuring that any missing or delayed data is considered during the analysis. + +## API's + + +### Create Experiment API -## CreateExperiment This is quick guide instructions to create experiments using input JSON as follows. For a more detailed guide, see [Create Experiment](/design/CreateExperiment.md) @@ -117,8 +163,8 @@ see [Create Experiment](/design/CreateExperiment.md) ``` - -## Update Metric Results + +### Update Results API Update metric results using input JSON as follows. For a more detailed guide, see [Update results](/design/UpdateResults.md) @@ -511,7 +557,8 @@ specific attribute causing the failures. ``` -## List Experiments + +## List Experiments API **Request with experiment name parameter** @@ -1586,7 +1633,8 @@ name parameter** Returns all the recommendations and all the results of the specified experiment. -## List Recommendations + +### List Recommendations API List recommendations output JSON as follows. Some parameters like CPU limit , ENV are optional. @@ -2452,8 +2500,8 @@ Time - `2022-12-20T17:55:05.000Z`** - -## Update Recommendations API + +### Update Recommendations API Generate the recommendations for a specific experiment based on provided parameters. From 49bb8da53ed4e4657a789109452f217f838f0fd3 Mon Sep 17 00:00:00 2001 From: bharathappali Date: Fri, 29 Sep 2023 17:02:13 +0530 Subject: [PATCH 34/36] Make updates Signed-off-by: bharathappali --- design/MonitoringModeAPI.md | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/design/MonitoringModeAPI.md b/design/MonitoringModeAPI.md index 5f3308ecd..3161999e0 100644 --- a/design/MonitoringModeAPI.md +++ b/design/MonitoringModeAPI.md @@ -10,9 +10,6 @@ Documentation still in progress stay tuned. 1. [Resource Analysis Terms and Defaults](#resource-analysis-terms-and-defaults) - [Terms, Duration & Threshold Table](#terms-duration--threshold-table) - - [Short Term](#short-term) - - [Medium Term](#medium-term) - - [Long Term](#long-term) 2. [API's](#apis) - [Create Experiment API](#create-experiment-api) @@ -57,35 +54,10 @@ Below are the default terms used in resource analysis, along with their respecti | Medium | 7 days | 6 hours | | Long | 15 days | 6 hours | - -##### Short Term +**Duration**: The "duration" in the term analysis refers to the amount of historical data taken into account when assessing resource utilization. - Duration: 24 hours - Threshold: 6 hours +**Threshold**: The "threshold" is an additional buffer period. It encompasses the term duration and extends an extra time duration. This buffer accommodates any potential data gaps or misses within the term window, ensuring a comprehensive analysis. -**Duration**: The "duration" in the short-term analysis refers to the amount of historical data taken into account when assessing resource utilization. In this case, it covers the most recent 24 hours of data. - -**Threshold**: The "threshold" is an additional buffer period. It encompasses the 24-hour duration and extends an extra six hours. This buffer accommodates any potential data gaps or misses within the 24-hour window, ensuring a comprehensive analysis. - - -##### Medium Term - - Duration: 7 days - Threshold: 6 hours - -**Duration**: The "duration" for the medium-term analysis extends further into the past, considering resource data from the last seven days. It provides a broader perspective on resource trends and utilization. - -**Threshold**: Similar to the short term, the "threshold" for the medium term includes an extra buffer of six hours. This buffer complements the seven-day duration, accounting for any data discrepancies or gaps within that timeframe. - - -##### Long Term - - Duration: 15 days - Threshold: 6 hours - -**Duration**: The "duration" in the long-term analysis offers insights into resource utilization over a more extended period, encompassing data from the last 15 days. This extended timeframe allows for a comprehensive evaluation of resource patterns. - -**Threshold**: Like the short and medium terms, the "threshold" for the long term includes a buffer period of six hours. This buffer enhances the 15-day duration, ensuring that any missing or delayed data is considered during the analysis. ## API's From 0dbb0c04605f2cd3c074159bf468fce331c50a4c Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Wed, 4 Oct 2023 21:13:11 +0530 Subject: [PATCH 35/36] merged from RM to mvp_demo Signed-off-by: msvinaykumar --- migrations/kruize_experiments_ddl.sql | 11 -- .../PerformanceRecommendationEngine.java | 104 +----------------- .../utils/RecommendationUtils.java | 10 -- .../ExperimentNameExistValidator.java | 56 ---------- .../analyzer/services/UpdateResults.java | 6 - .../common/annotations/json/Exclude.java | 1 + 6 files changed, 4 insertions(+), 184 deletions(-) delete mode 100644 src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java diff --git a/migrations/kruize_experiments_ddl.sql b/migrations/kruize_experiments_ddl.sql index 01f2a49fd..8d9002b71 100644 --- a/migrations/kruize_experiments_ddl.sql +++ b/migrations/kruize_experiments_ddl.sql @@ -1,20 +1,9 @@ create table IF NOT EXISTS kruize_experiments (experiment_id varchar(255) not null, cluster_name varchar(255), datasource jsonb, experiment_name varchar(255), extended_data jsonb, meta_data jsonb, mode varchar(255), performance_profile varchar(255), status varchar(255), target_cluster varchar(255), version varchar(255), primary key (experiment_id)); create table IF NOT EXISTS kruize_performance_profiles (name varchar(255) not null, k8s_type varchar(255), profile_version float(53) not null, slo jsonb, primary key (name)); -<<<<<<< HEAD -create table IF NOT EXISTS kruize_recommendations (interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) not null, extended_data jsonb, version varchar(255), primary key (cluster_name, experiment_name, interval_end_time)) PARTITION BY RANGE (interval_end_time); -create table IF NOT EXISTS kruize_results (interval_start_time timestamp(6) not null, interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) not null, duration_minutes float(53) not null, extended_data jsonb, meta_data jsonb, version varchar(255), primary key (cluster_name, experiment_name, interval_end_time, interval_start_time)) PARTITION BY RANGE (interval_end_time); -alter table if exists kruize_experiments add constraint UK_experiment_name unique (experiment_name); -create index IF NOT EXISTS idx_recommendation_experiment_name on kruize_recommendations (experiment_name); -create index IF NOT EXISTS idx_recommendation_cluster_name on kruize_recommendations (cluster_name); -create index IF NOT EXISTS idx_recommendation_interval_end_time on kruize_recommendations (interval_end_time); -create index IF NOT EXISTS idx_result_experiment_name on kruize_results (experiment_name); -create index IF NOT EXISTS idx_result_cluster_name on kruize_results (cluster_name); -======= create table IF NOT EXISTS kruize_recommendations (interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255), extended_data jsonb, version varchar(255), primary key (experiment_name, interval_end_time)) PARTITION BY RANGE (interval_end_time); create table IF NOT EXISTS kruize_results (interval_start_time timestamp(6) not null, interval_end_time timestamp(6) not null, experiment_name varchar(255) not null, cluster_name varchar(255) , duration_minutes float(53) not null, extended_data jsonb, meta_data jsonb, version varchar(255), primary key (experiment_name, interval_end_time, interval_start_time)) PARTITION BY RANGE (interval_end_time); alter table if exists kruize_experiments add constraint UK_experiment_name unique (experiment_name); create index IF NOT EXISTS idx_recommendation_experiment_name on kruize_recommendations (experiment_name); create index IF NOT EXISTS idx_recommendation_interval_end_time on kruize_recommendations (interval_end_time); create index IF NOT EXISTS idx_result_experiment_name on kruize_results (experiment_name); ->>>>>>> upstream/remote_monitoring create index IF NOT EXISTS idx_result_interval_end_time on kruize_results (interval_end_time); diff --git a/src/main/java/com/autotune/analyzer/recommendations/engine/PerformanceRecommendationEngine.java b/src/main/java/com/autotune/analyzer/recommendations/engine/PerformanceRecommendationEngine.java index ffa8e16d2..f16027593 100644 --- a/src/main/java/com/autotune/analyzer/recommendations/engine/PerformanceRecommendationEngine.java +++ b/src/main/java/com/autotune/analyzer/recommendations/engine/PerformanceRecommendationEngine.java @@ -41,7 +41,7 @@ import static com.autotune.analyzer.recommendations.RecommendationConstants.RecommendationValueConstants.DEFAULT_MEMORY_THRESHOLD; import static com.autotune.analyzer.utils.AnalyzerConstants.PercentileConstants.*; -public class PerformanceRecommendationEngine implements KruizeRecommendationEngine{ +public class PerformanceRecommendationEngine implements KruizeRecommendationEngine { private static final Logger LOGGER = LoggerFactory.getLogger(PerformanceRecommendationEngine.class); private String name; private String key; @@ -57,38 +57,6 @@ public PerformanceRecommendationEngine(String name) { this.name = name; } - private static Timestamp getMonitoringStartTime(HashMap resultsHashMap, - DurationBasedRecommendationSubCategory durationBasedRecommendationSubCategory, - Timestamp endTime) { - - // Convert the HashMap to a TreeMap to maintain sorted order based on IntervalEndTime - TreeMap sortedResultsHashMap = new TreeMap<>(Collections.reverseOrder()); - sortedResultsHashMap.putAll(resultsHashMap); - - double sum = 0.0; - Timestamp intervalEndTime = null; - Timestamp thresholdTime = calculateThresholdTimeBasedOnTerm(durationBasedRecommendationSubCategory, endTime); - for (Timestamp timestamp : sortedResultsHashMap.keySet()) { - if (!timestamp.after(endTime)) { - if (timestamp.before(thresholdTime)) { - // Breaking condition not met so we can be sure that data is not sufficient hence return null - return null; - } - sum = sum + sortedResultsHashMap.get(timestamp).getDurationInMinutes(); - if (sum >= durationBasedRecommendationSubCategory.getGetDurationLowerBound()) { - // Storing the timestamp value in startTimestamp variable to return - intervalEndTime = timestamp; - break; - } - - } - } - try { - return sortedResultsHashMap.get(intervalEndTime).getIntervalStartTime(); - } catch (NullPointerException npe) { - return null; - } - } /** * Calculate the number of pods being used as per the latest results @@ -522,7 +490,7 @@ private boolean populateRecommendation(String recommendationTerm, RecommendationNotification recommendationNotification = new RecommendationNotification(RecommendationConstants.RecommendationNotification.ERROR_NUM_PODS_CANNOT_BE_ZERO); notifications.add(recommendationNotification); LOGGER.debug("Number of pods cannot be zero"); - isSuccess = false; + isSuccess = false; } else if (numPods < 0) { RecommendationNotification recommendationNotification = new RecommendationNotification(RecommendationConstants.RecommendationNotification.ERROR_NUM_PODS_CANNOT_BE_NEGATIVE); notifications.add(recommendationNotification); @@ -1063,7 +1031,7 @@ public MappedRecommendationForEngine generateRecommendation(Timestamp monitoring cpuThreshold, memoryThreshold ); - } else { + } else { RecommendationNotification notification = new RecommendationNotification( RecommendationConstants.RecommendationNotification.INFO_NOT_ENOUGH_DATA); @@ -1075,70 +1043,4 @@ public MappedRecommendationForEngine generateRecommendation(Timestamp monitoring public void validateRecommendations() { } - - @Override - public boolean checkIfMinDataAvailable(ContainerData containerData) { - // Check if data available - if (null == containerData || null == containerData.getResults() || containerData.getResults().isEmpty()) { - return false; - } - // Initiate to the first sub category available - DurationBasedRecommendationSubCategory categoryToConsider = (DurationBasedRecommendationSubCategory) this.category.getRecommendationSubCategories()[0]; - // Loop over categories to set the least category - for (RecommendationSubCategory recommendationSubCategory : this.category.getRecommendationSubCategories()) { - DurationBasedRecommendationSubCategory durationBasedRecommendationSubCategory = (DurationBasedRecommendationSubCategory) recommendationSubCategory; - if (durationBasedRecommendationSubCategory.getDuration() < categoryToConsider.getDuration()) { - categoryToConsider = durationBasedRecommendationSubCategory; - } - } - // Set bounds to check if we get minimum requirement satisfied - double lowerBound = categoryToConsider.getGetDurationLowerBound(); - double sum = 0.0; - // Loop over the data to check if there is min data available - for (IntervalResults intervalResults : containerData.getResults().values()) { - sum = sum + intervalResults.getDurationInMinutes(); - // We don't consider upper bound to check if sum is in-between as we may over shoot and end-up resulting false - if (sum >= lowerBound) - return true; - } - return false; - } - - private static Timestamp calculateThresholdTimeBasedOnTerm(DurationBasedRecommendationSubCategory durationBasedRecommendationSubCategory, Timestamp endTime) { - // Check for null - if (null == durationBasedRecommendationSubCategory || null == endTime) - return null; - // Initialise threshold time - Timestamp thresholdTime = null; - - // Extract the duration as count - int count = durationBasedRecommendationSubCategory.getDuration(); - // Extract units - TimeUnit units = durationBasedRecommendationSubCategory.getRecommendationDurationUnits(); - - // Assuming units is hours by default - int totalDurationInHrs = count; - - // Checking if it's days - if (units == TimeUnit.DAYS) { - totalDurationInHrs = count * KruizeConstants.TimeConv.NO_OF_HOURS_PER_DAY; - } - // TODO: Add checks for other timeunits like minutes, weeks & months if needed later - - // Add Threshold based on term - if (durationBasedRecommendationSubCategory.getSubCategory().equalsIgnoreCase(KruizeConstants.JSONKeys.SHORT_TERM)) - totalDurationInHrs = totalDurationInHrs + THRESHOLD_HRS_SHORT_TERM; - else if (durationBasedRecommendationSubCategory.getSubCategory().equalsIgnoreCase(KruizeConstants.JSONKeys.MEDIUM_TERM)) - totalDurationInHrs = totalDurationInHrs + THRESHOLD_HRS_MEDIUM_TERM; - else if (durationBasedRecommendationSubCategory.getSubCategory().equalsIgnoreCase(KruizeConstants.JSONKeys.LONG_TERM)) - totalDurationInHrs = totalDurationInHrs + THRESHOLD_HRS_LONG_TERM; - - // Remove the number of hours from end time - long endTimeMillis = endTime.getTime(); - long startTimeMillis = endTimeMillis - TimeUnit.HOURS.toMillis(totalDurationInHrs); - - thresholdTime = new Timestamp(startTimeMillis); - - return thresholdTime; - } } diff --git a/src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java b/src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java index e2da0e19b..08388e3c3 100644 --- a/src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java +++ b/src/main/java/com/autotune/analyzer/recommendations/utils/RecommendationUtils.java @@ -162,15 +162,5 @@ public static RecommendationNotification getNotificationForTermAvailability(Reco } - public class RecommendationUtils { - public static int getThreshold(int value, int failoverPercentage, boolean direction) { - if (direction) { - return Math.round(value + value * (failoverPercentage / 100.0f)); - } else { - return Math.round(value - value * (failoverPercentage / 100.0f)); - } - } - } - } 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 deleted file mode 100644 index 2d88053d8..000000000 --- a/src/main/java/com/autotune/analyzer/serviceObjects/verification/validators/ExperimentNameExistValidator.java +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * 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.verification.annotators.ExperimentNameExist; -import com.autotune.analyzer.services.UpdateResults; -import com.autotune.database.service.ExperimentDBService; -import jakarta.validation.ConstraintValidator; -import jakarta.validation.ConstraintValidatorContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ExperimentNameExistValidator implements ConstraintValidator { - private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentNameExistValidator.class); - - // You can inject your database access/repository here to fetch the data - - @Override - public boolean isValid(String experimentName, ConstraintValidatorContext context) { - boolean success = false; - String errorMessage = ""; - if (!UpdateResults.mainKruizeExperimentMAP.containsKey(experimentName)) { - // Retrieve the data from the database - try { - new ExperimentDBService().loadExperimentFromDBByName(UpdateResults.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 (UpdateResults.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/services/UpdateResults.java b/src/main/java/com/autotune/analyzer/services/UpdateResults.java index f29d0fbee..54b34ec05 100644 --- a/src/main/java/com/autotune/analyzer/services/UpdateResults.java +++ b/src/main/java/com/autotune/analyzer/services/UpdateResults.java @@ -56,14 +56,10 @@ public class UpdateResults extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger LOGGER = LoggerFactory.getLogger(UpdateResults.class); public static ConcurrentHashMap performanceProfilesMap = new ConcurrentHashMap<>(); - public static ConcurrentHashMap mainKruizeExperimentMAP; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - mainKruizeExperimentMAP = (ConcurrentHashMap) config.getServletContext().getAttribute(AnalyzerConstants.EXPERIMENT_MAP); - if (mainKruizeExperimentMAP == null) - mainKruizeExperimentMAP = new ConcurrentHashMap<>(); } @Override @@ -83,8 +79,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) ExperimentInitiator experimentInitiator = new ExperimentInitiator(); experimentInitiator.validateAndAddExperimentResults(updateResultsAPIObjects); List failureAPIObjs = experimentInitiator.getFailedUpdateResultsAPIObjects(); - if (initialSize != mainKruizeExperimentMAP.size()) - request.getServletContext().setAttribute(AnalyzerConstants.EXPERIMENT_MAP, mainKruizeExperimentMAP); List jsonObjectList = new ArrayList<>(); if (failureAPIObjs.size() > 0) { failureAPIObjs.forEach( diff --git a/src/main/java/com/autotune/common/annotations/json/Exclude.java b/src/main/java/com/autotune/common/annotations/json/Exclude.java index f78b39f1a..30fe81098 100644 --- a/src/main/java/com/autotune/common/annotations/json/Exclude.java +++ b/src/main/java/com/autotune/common/annotations/json/Exclude.java @@ -24,3 +24,4 @@ @Target(ElementType.FIELD) public @interface Exclude { } + From 6724e35695d2b167a6a08519482442e131eccc89 Mon Sep 17 00:00:00 2001 From: msvinaykumar Date: Thu, 5 Oct 2023 15:42:06 +0530 Subject: [PATCH 36/36] incorporated review comments Signed-off-by: msvinaykumar --- .../minikube/kruize-crc-minikube.yaml | 2 +- .../openshift/kruize-crc-openshift.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml index 6a493d21f..f511eae52 100644 --- a/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml +++ b/manifests/crc/default-db-included-installation/minikube/kruize-crc-minikube.yaml @@ -208,7 +208,7 @@ spec: spec: containers: - name: kruizecronjob - image: kruize/autotune_operator:0.0.19_rm + image: kruize/autotune_operator:0.0.19.2_rm imagePullPolicy: Always volumeMounts: - name: config-volume diff --git a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml index da5b41c57..f0f9d46b0 100644 --- a/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml +++ b/manifests/crc/default-db-included-installation/openshift/kruize-crc-openshift.yaml @@ -261,7 +261,7 @@ spec: spec: containers: - name: kruizecronjob - image: kruize/autotune_operator:0.0.19_rm + image: kruize/autotune_operator:0.0.19.2_rm imagePullPolicy: Always volumeMounts: - name: config-volume