Skip to content

Commit

Permalink
Merge pull request #1262 from shreyabiradar07/feat/delete-metric-profile
Browse files Browse the repository at this point in the history
Add Delete Metric Profile API with name query parameter
  • Loading branch information
chandrams authored Aug 26, 2024
2 parents 5da0355 + f4c4ff6 commit 52494fd
Show file tree
Hide file tree
Showing 14 changed files with 2,238 additions and 11 deletions.
1,075 changes: 1,075 additions & 0 deletions design/KruizeLocalAPI.md

Large diffs are not rendered by default.

1,019 changes: 1,019 additions & 0 deletions design/MetricProfileAPI.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,4 @@ slo:

aggregation_functions:
- function: max
query: 'max by(namespace,container) (last_over_time((timestamp(container_cpu_usage_seconds_total{namespace=\"$NAMESPACE$\",container=\"$CONTAINER_NAME$\"} > 0))[15d:]))'
query: 'max by(namespace,container) (last_over_time((timestamp(container_cpu_usage_seconds_total{namespace=\"$NAMESPACE$\",container=\"$CONTAINER_NAME$\"} > 0))[15d:]))'
1 change: 1 addition & 0 deletions src/main/java/com/autotune/analyzer/Analyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static void addServlets(ServletContextHandler context) {
context.addServlet(PerformanceProfileService.class, ServerContext.LIST_PERF_PROFILES);
context.addServlet(MetricProfileService.class, ServerContext.CREATE_METRIC_PROFILE);
context.addServlet(MetricProfileService.class, ServerContext.LIST_METRIC_PROFILES);
context.addServlet(MetricProfileService.class, ServerContext.DELETE_METRIC_PROFILE);
context.addServlet(ListDatasources.class, ServerContext.LIST_DATASOURCES);
context.addServlet(DSMetadataService.class, ServerContext.DATASOURCE_METADATA);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2022 Red Hat, IBM Corporation and others.
* Copyright (c) 2022, 2024 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.autotune.analyzer.kruizeObject.KruizeObject;
import com.autotune.analyzer.kruizeObject.RecommendationSettings;
import com.autotune.analyzer.performanceProfiles.MetricProfileCollection;
import com.autotune.analyzer.performanceProfiles.PerformanceProfile;
import com.autotune.analyzer.plots.PlotManager;
import com.autotune.analyzer.recommendations.ContainerRecommendations;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.autotune.common.data.ValidationOutputData;
import com.autotune.common.data.metrics.Metric;
import com.autotune.common.data.result.ContainerData;
import com.autotune.database.dao.ExperimentDAOImpl;
import com.autotune.database.service.ExperimentDBService;
import com.autotune.utils.KruizeConstants;
import com.autotune.utils.KruizeSupportedTypes;
Expand Down Expand Up @@ -225,17 +226,70 @@ protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws Se
}

/**
* TODO: Need to implement
* Delete Metric profile
* Handles the DELETE request for deleting metric profile - DELETE /deleteMetricProfile
*
* @param req
* @param resp
* Supported Query Parameters -
* name - metric profile name to be deleted(required)
*
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doDelete(req, resp);
protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType(JSON_CONTENT_TYPE);
response.setCharacterEncoding(CHARACTER_ENCODING);
response.setStatus(HttpServletResponse.SC_OK);

ConcurrentHashMap<String, PerformanceProfile> metricProfilesMap = new ConcurrentHashMap<>();
String metricProfileName = request.getParameter(AnalyzerConstants.PerformanceProfileConstants.METRIC_PROFILE_NAME);

if (null == metricProfileName || metricProfileName.isEmpty()) {
sendErrorResponse(
response,
new Exception(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.MISSING_METRIC_PROFILE_NAME_EXCPTN),
HttpServletResponse.SC_BAD_REQUEST,
String.format(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.MISSING_METRIC_PROFILE_NAME_MSG)
);
return;
}

try {
// load specified metric profile
loadMetricProfilesFromCollection(metricProfilesMap, metricProfileName);

// Check if metric profile exists
if (!metricProfilesMap.isEmpty() && metricProfilesMap.containsKey(metricProfileName)) {
try {
// Deletes database and in-memory metric profile object stored
deleteMetricProfile(metricProfileName);
metricProfilesMap.remove(metricProfileName);
} catch (Exception e) {
sendErrorResponse(
response,
e,
HttpServletResponse.SC_BAD_REQUEST,
e.getMessage());
return;
}
} else {
sendErrorResponse(
response,
new Exception(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.INVALID_METRIC_PROFILE_NAME_EXCPTN),
HttpServletResponse.SC_BAD_REQUEST,
String.format(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.INVALID_METRIC_PROFILE_NAME_MSG, metricProfileName)
);
return;
}

sendSuccessResponse(response, String.format(KruizeConstants.MetricProfileAPIMessages.DELETE_METRIC_PROFILE_SUCCESS_MSG, metricProfileName));

} catch (Exception e) {
LOGGER.error(e.getMessage());
sendErrorResponse(response, e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
}

/**
Expand Down Expand Up @@ -300,6 +354,24 @@ private void loadAllMetricProfilesFromCollection(Map<String, PerformanceProfile>
}
}

private void deleteMetricProfile(String metricProfileName) {
ValidationOutputData deletedMetricProfileFromDB = null;
try {
// delete the metric profile from DB
deletedMetricProfileFromDB = new ExperimentDAOImpl().deleteKruizeMetricProfileEntryByName(metricProfileName);
if (deletedMetricProfileFromDB.isSuccess()) {
// remove in-memory metric profile
MetricProfileCollection.getInstance().getMetricProfileCollection().remove(metricProfileName);
LOGGER.debug(KruizeConstants.MetricProfileAPIMessages.DELETE_METRIC_PROFILE_FROM_DB_SUCCESS_MSG);
} else {
LOGGER.error(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.DELETE_METRIC_PROFILE_FROM_DB_FAILURE_MSG, deletedMetricProfileFromDB.getMessage());
}

} catch (Exception e) {
LOGGER.error(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.DELETE_METRIC_PROFILE_FAILURE_MSG, e.getMessage());
}
}

private Gson createGsonObject() {
return new GsonBuilder()
.disableHtmlEscaping()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,14 +480,14 @@ public static final class PerformanceProfileConstants {
public static final String PERFORMANCE_PROFILE_PKG = "com.autotune.analyzer.performanceProfiles.PerformanceProfileInterface.";
public static final String DEFAULT_PROFILE = "default";

// Perf profile names
public static final String RESOURCE_OPT_OPENSHIFT_PROFILE = "resource-optimization-openshift";
public static final String RESOURCE_OPT_LOCAL_MON_PROFILE = "resource-optimization-local-monitoring";

//Metric profile constants
public static final String DEFAULT_API_VERSION = "recommender.com/v1";
public static final String DEFAULT_KIND = "KruizePerformanceProfile";

// Perf profile names
public static final String RESOURCE_OPT_OPENSHIFT_PROFILE = "resource-optimization-openshift";
public static final String RESOURCE_OPT_LOCAL_MON_PROFILE = "resource-optimization-local-monitoring";

public static final Map<String, String> PerfProfileNames = Map.of(
RESOURCE_OPT_OPENSHIFT_PROFILE, "ResourceOptimizationOpenshiftImpl",
RESOURCE_OPT_LOCAL_MON_PROFILE, "ResourceOptimizationOpenshiftImpl"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.autotune.operator.KruizeDeploymentInfo;
import com.autotune.utils.KruizeConstants;
import com.autotune.utils.KruizeSupportedTypes;
import software.amazon.awssdk.services.cloudwatchlogs.endpoints.internal.Value;

import java.util.Arrays;

Expand Down Expand Up @@ -234,6 +235,19 @@ public ListMetricProfileAPI() {
public static final String NO_METRIC_PROFILES_EXCPTN = "No metric profile";
public static final String NO_METRIC_PROFILES = "No metric profiles found!";
}

public static final class DeleteMetricProfileAPI {
public DeleteMetricProfileAPI() {
}
public static final String INVALID_METRIC_PROFILE_NAME_EXCPTN = "Invalid Metric Profile Name";
public static final String INVALID_METRIC_PROFILE_NAME_MSG = "Given metric profile name - %s either does not exist or is not valid";
public static final String MISSING_METRIC_PROFILE_NAME_EXCPTN = "Missing Metric Profile Name";
public static final String MISSING_METRIC_PROFILE_NAME_MSG = "Missing metric profile 'name' parameter";
public static final String DELETE_METRIC_PROFILE_FROM_DB_FAILURE_MSG = "Failed to delete metric profile from DB: %s";
public static final String DELETE_METRIC_PROFILE_FAILURE_MSG = "Failed to delete the specified metric profile data: %s";
public static final String DELETE_METRIC_PROFILE_ENTRY_NOT_FOUND_WITH_NAME = "KruizeMetricProfileEntry not found with metric profile name: ";
public static final String DELETE_METRIC_PROFILE_ENTRY_ERROR_MSG = "Not able to delete metric profile for metric profile {} due to {}";
}
}

public static final class ConversionErrors {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/autotune/database/dao/ExperimentDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ public interface ExperimentDAO {
// Load a single Metric Profile based on name
List<KruizeMetricProfileEntry> loadMetricProfileByName(String metricProfileName) throws Exception;

// Delete metric profile for the specified metric profile name
public ValidationOutputData deleteKruizeMetricProfileEntryByName(String metricProfileName);

// Load all recommendations of a particular experiment and interval end Time
KruizeRecommendationEntry loadRecommendationsByExperimentNameAndDate(String experimentName, String cluster_name, Timestamp interval_end_time) throws Exception;

Expand Down
38 changes: 38 additions & 0 deletions src/main/java/com/autotune/database/dao/ExperimentDAOImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,44 @@ public ValidationOutputData deleteKruizeDSMetadataEntryByName(String dataSourceN
return validationOutputData;
}

/**
* Delete metric profile with specified profile name
* This deletes the metadata from the KruizeMetricProfileEntry table
* @param metricProfileName
* @return
*/
@Override
public ValidationOutputData deleteKruizeMetricProfileEntryByName(String metricProfileName) {
ValidationOutputData validationOutputData = new ValidationOutputData(false, null, null);
Transaction tx = null;
try (Session session = KruizeHibernateUtil.getSessionFactory().openSession()) {
try {
tx = session.beginTransaction();
Query query = session.createQuery(DELETE_FROM_METRIC_PROFILE_BY_PROFILE_NAME, null);
query.setParameter("metricProfileName", metricProfileName);
int deletedCount = query.executeUpdate();

if (deletedCount == 0) {
validationOutputData.setSuccess(false);
validationOutputData.setMessage(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.DELETE_METRIC_PROFILE_ENTRY_NOT_FOUND_WITH_NAME + metricProfileName);
} else {
validationOutputData.setSuccess(true);
}
tx.commit();
} catch (HibernateException e) {
LOGGER.error(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.DELETE_METRIC_PROFILE_ENTRY_ERROR_MSG, metricProfileName, 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(AnalyzerErrorConstants.APIErrors.DeleteMetricProfileAPI.DELETE_METRIC_PROFILE_ENTRY_ERROR_MSG, metricProfileName, e.getMessage());
}
return validationOutputData;
}

@Override
public List<KruizeExperimentEntry> loadAllExperiments() throws Exception {
//todo load only experimentStatus=inprogress , playback may not require completed experiments
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public static final class SQLQUERY {
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 DELETE_FROM_METADATA_BY_DATASOURCE_NAME = "DELETE FROM KruizeDSMetadataEntry km WHERE km.datasource_name = :dataSourceName";
public static final String DELETE_FROM_METRIC_PROFILE_BY_PROFILE_NAME = "DELETE FROM KruizeMetricProfileEntry km WHERE km.name = :metricProfileName";
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 String SELECT_ALL_KRUIZE_TABLES = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' " +
"and (table_name like 'kruize_results_%' or table_name like 'kruize_recommendations_%') ";
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/autotune/utils/KruizeConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public static class MetricProfileAPIMessages {
public static final String VIEW_METRIC_PROFILES_MSG = " View Metric Profiles at /listMetricProfiles";
public static final String LOAD_METRIC_PROFILE_FAILURE = "Failed to load saved metric profile data: {}";
public static final String ADD_METRIC_PROFILE_TO_DB_WITH_VERSION = "Added Metric Profile : {} into the DB with version: {}";
public static final String DELETE_METRIC_PROFILE_SUCCESS_MSG = "Metric profile: %s deleted successfully.";
public static final String DELETE_METRIC_PROFILE_FROM_DB_SUCCESS_MSG = "Metric profile deleted successfully from the DB.";
}

public static class MetricProfileConstants {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/autotune/utils/ServerContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class ServerContext {
public static final String LIST_PERF_PROFILES = ROOT_CONTEXT + "listPerformanceProfiles";
public static final String CREATE_METRIC_PROFILE = ROOT_CONTEXT + "createMetricProfile";
public static final String LIST_METRIC_PROFILES = ROOT_CONTEXT + "listMetricProfiles";
public static final String DELETE_METRIC_PROFILE = ROOT_CONTEXT + "deleteMetricProfile";

public static final String KRUIZE_SERVER_URL = "http://localhost:" + KRUIZE_SERVER_PORT;
public static final String SEARCH_SPACE_END_POINT = KRUIZE_SERVER_URL + SEARCH_SPACE;
Expand Down

0 comments on commit 52494fd

Please sign in to comment.