diff --git a/src/main/java/com/autotune/analyzer/adapters/KruizeObjectAdapter.java b/src/main/java/com/autotune/analyzer/adapters/KruizeObjectAdapter.java new file mode 100644 index 000000000..b8b56ffd9 --- /dev/null +++ b/src/main/java/com/autotune/analyzer/adapters/KruizeObjectAdapter.java @@ -0,0 +1,23 @@ +package com.autotune.analyzer.adapters; + +import com.autotune.analyzer.kruizeObject.KruizeObject; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +public class KruizeObjectAdapter implements JsonSerializer { + @Override + public JsonElement serialize(KruizeObject obj, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jsonObject = context.serialize(obj).getAsJsonObject(); + + // Replace the experiment_type field + String typeStr = obj.getExperimentTypeString(); + jsonObject.remove("experiment_type"); + jsonObject.addProperty("experiment_type", typeStr); + + return jsonObject; + } +} diff --git a/src/main/java/com/autotune/analyzer/experiment/ExperimentValidation.java b/src/main/java/com/autotune/analyzer/experiment/ExperimentValidation.java index f4055a94e..1dd23a466 100644 --- a/src/main/java/com/autotune/analyzer/experiment/ExperimentValidation.java +++ b/src/main/java/com/autotune/analyzer/experiment/ExperimentValidation.java @@ -21,6 +21,7 @@ import com.autotune.analyzer.recommendations.ContainerRecommendations; import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.analyzer.utils.ExperimentTypeUtil; import com.autotune.common.data.ValidationOutputData; import com.autotune.common.data.metrics.Metric; import com.autotune.common.data.result.ContainerData; @@ -373,7 +374,7 @@ public ValidationOutputData validateMandatoryFields(KruizeObject expObj) { String depType = ""; if (expObj.getExperiment_usecase_type().isRemote_monitoring()) { // In case of RM, kubernetes_obj is mandatory - if (expObj.getExperimentType().equals(AnalyzerConstants.ExperimentType.CONTAINER)) { + if (AnalyzerConstants.ExperimentBitMask.CONTAINER_BIT.isSet(expObj.getExperimentType())) { mandatoryDeploymentSelector = Collections.singletonList(AnalyzerConstants.KUBERNETES_OBJECTS); // check for valid k8stype for (K8sObject k8sObject : expObj.getKubernetes_objects()) { @@ -395,15 +396,27 @@ public ValidationOutputData validateMandatoryFields(KruizeObject expObj) { } } // Namespace experiment validation for both remote and local monitoring - if (expObj.getExperimentType().equals(AnalyzerConstants.ExperimentType.NAMESPACE)){ + if (AnalyzerConstants.ExperimentBitMask.NAMESPACE_BIT.isSet(expObj.getExperimentType())){ for (K8sObject k8sObject : expObj.getKubernetes_objects()) { if (null == k8sObject.getNamespaceDataMap() || k8sObject.getNamespaceDataMap().isEmpty()) { - errorMsg = errorMsg.concat(String.format(AnalyzerErrorConstants.APIErrors.CreateExperimentAPI.MISSING_NAMESPACE_DATA, expObj.getExperimentType().toString())); + errorMsg = errorMsg.concat( + String.format( + AnalyzerErrorConstants.APIErrors.CreateExperimentAPI.MISSING_NAMESPACE_DATA, + ExperimentTypeUtil.getExperimentTypeFromBitMask( + expObj.getExperimentType() + ).toString() + )); missingNamespaceData = true; } else { for (NamespaceData namespaceData : k8sObject.getNamespaceDataMap().values()) { if (null == namespaceData.getNamespace_name()) { - errorMsg = errorMsg.concat(String.format(AnalyzerErrorConstants.APIErrors.CreateExperimentAPI.MISSING_NAMESPACE, expObj.getExperimentType().toString())); + errorMsg = errorMsg.concat( + String.format( + AnalyzerErrorConstants.APIErrors.CreateExperimentAPI.MISSING_NAMESPACE, + ExperimentTypeUtil.getExperimentTypeFromBitMask( + expObj.getExperimentType() + ).toString() + )); missingNamespaceData = true; break; } diff --git a/src/main/java/com/autotune/analyzer/kruizeObject/KruizeObject.java b/src/main/java/com/autotune/analyzer/kruizeObject/KruizeObject.java index 7fb85f91f..91b251922 100644 --- a/src/main/java/com/autotune/analyzer/kruizeObject/KruizeObject.java +++ b/src/main/java/com/autotune/analyzer/kruizeObject/KruizeObject.java @@ -41,7 +41,7 @@ *

* Refer to examples dir for a reference AutotuneObject yaml. */ -public final class KruizeObject implements ExperimentTypeAware { +public final class KruizeObject { @SerializedName("version") private String apiVersion; @@ -53,8 +53,7 @@ public final class KruizeObject implements ExperimentTypeAware { @SerializedName("datasource") private String datasource; @SerializedName(KruizeConstants.JSONKeys.EXPERIMENT_TYPE) //TODO: to be used in future - @JsonAdapter(ExperimentTypeUtil.ExperimentTypeSerializer.class) - private AnalyzerConstants.ExperimentType experimentType; + private long experimentType; @SerializedName("default_updater") private String defaultUpdater; private String namespace; // TODO: Currently adding it at this level with an assumption that there is only one entry in k8s object needs to be changed @@ -370,11 +369,11 @@ public void setDataSource(String datasource) { this.datasource = datasource; } - public AnalyzerConstants.ExperimentType getExperimentType() { + public long getExperimentType() { return experimentType; } - public void setExperimentType(AnalyzerConstants.ExperimentType experimentType) { + public void setExperimentType(long experimentType) { this.experimentType = experimentType; } @@ -425,12 +424,12 @@ public String toString() { '}'; } - @Override + public boolean isNamespaceExperiment() { return ExperimentTypeUtil.isNamespaceExperiment(experimentType); } - @Override + public boolean isContainerExperiment() { return ExperimentTypeUtil.isContainerExperiment(experimentType); } @@ -453,4 +452,9 @@ private static double getTermThresholdInDays(String term, Double measurement_dur return ((double) measurement_duration * minDataPoints / (KruizeConstants.TimeConv.NO_OF_HOURS_PER_DAY * KruizeConstants.TimeConv.NO_OF_MINUTES_PER_HOUR)); } + + public String getExperimentTypeString() { + AnalyzerConstants.ExperimentType type = ExperimentTypeUtil.getExperimentTypeFromBitMask(this.experimentType); + return type.toString().toLowerCase(); + } } diff --git a/src/main/java/com/autotune/analyzer/recommendations/engine/RecommendationEngine.java b/src/main/java/com/autotune/analyzer/recommendations/engine/RecommendationEngine.java index d693f19a6..29c206d82 100644 --- a/src/main/java/com/autotune/analyzer/recommendations/engine/RecommendationEngine.java +++ b/src/main/java/com/autotune/analyzer/recommendations/engine/RecommendationEngine.java @@ -19,6 +19,7 @@ import com.autotune.analyzer.recommendations.utils.RecommendationUtils; import com.autotune.analyzer.utils.AnalyzerConstants; import com.autotune.analyzer.utils.AnalyzerErrorConstants; +import com.autotune.analyzer.utils.ExperimentTypeUtil; import com.autotune.common.data.ValidationOutputData; import com.autotune.common.data.metrics.*; import com.autotune.common.data.result.ContainerData; @@ -2044,8 +2045,11 @@ private void fetchNamespaceMetricsBasedOnDataSourceAndProfile(KruizeObject kruiz } - List namespaceMetricList = filterMetricsBasedOnExpTypeAndK8sObject(metricProfile, - AnalyzerConstants.MetricName.namespaceMaxDate.name(), kruizeObject.getExperimentType()); + List namespaceMetricList = filterMetricsBasedOnExpTypeAndK8sObject( + metricProfile, + AnalyzerConstants.MetricName.namespaceMaxDate.name(), + ExperimentTypeUtil.getExperimentTypeFromBitMask(kruizeObject.getExperimentType()) + ); // Iterate over metrics and aggregation functions for (Metric metricEntry : namespaceMetricList) { @@ -2276,8 +2280,11 @@ private void fetchContainerMetricsBasedOnDataSourceAndProfile(KruizeObject kruiz MetricResults metricResults = null; MetricAggregationInfoResults metricAggregationInfoResults = null; - List metricList = filterMetricsBasedOnExpTypeAndK8sObject(metricProfile, - AnalyzerConstants.MetricName.maxDate.name(), kruizeObject.getExperimentType()); + List metricList = filterMetricsBasedOnExpTypeAndK8sObject( + metricProfile, + AnalyzerConstants.MetricName.maxDate.name(), + ExperimentTypeUtil.getExperimentTypeFromBitMask(kruizeObject.getExperimentType()) + ); List acceleratorFunctions = Arrays.asList( AnalyzerConstants.MetricName.acceleratorCoreUsage.toString(), diff --git a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java index f812ca682..7b8730802 100644 --- a/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java +++ b/src/main/java/com/autotune/analyzer/serviceObjects/Converters.java @@ -9,6 +9,7 @@ import com.autotune.analyzer.recommendations.objects.MappedRecommendationForTimestamp; import com.autotune.analyzer.recommendations.utils.RecommendationUtils; import com.autotune.analyzer.utils.AnalyzerConstants; +import com.autotune.analyzer.utils.ExperimentTypeUtil; import com.autotune.common.data.ValidationOutputData; import com.autotune.common.data.metrics.*; import com.autotune.common.data.result.ContainerData; @@ -79,7 +80,7 @@ public static KruizeObject convertCreateExperimentAPIObjToKruizeObject(CreateExp kruizeObject.setMode(createExperimentAPIObject.getMode()); kruizeObject.setPerformanceProfile(createExperimentAPIObject.getPerformanceProfile()); kruizeObject.setDataSource(createExperimentAPIObject.getDatasource()); - kruizeObject.setExperimentType(createExperimentAPIObject.getExperimentType()); + kruizeObject.setExperimentType(ExperimentTypeUtil.getExperimentType(createExperimentAPIObject.getExperimentType())); kruizeObject.setSloInfo(createExperimentAPIObject.getSloInfo()); kruizeObject.setTrial_settings(createExperimentAPIObject.getTrialSettings()); RecommendationSettings recommendationSettings = new RecommendationSettings(); @@ -158,7 +159,9 @@ public static ListRecommendationsAPIObject convertKruizeObjectToListRecommendati listRecommendationsAPIObject.setApiVersion(AnalyzerConstants.VersionConstants.APIVersionConstants.CURRENT_LIST_RECOMMENDATIONS_VERSION); listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); - listRecommendationsAPIObject.setExperimentType(kruizeObject.getExperimentType()); + listRecommendationsAPIObject.setExperimentType( + ExperimentTypeUtil.getExperimentTypeFromBitMask(kruizeObject.getExperimentType()) + ); List kubernetesAPIObjects = new ArrayList<>(); KubernetesAPIObject kubernetesAPIObject; 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 0dfcab380..821358764 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 @@ -87,7 +87,7 @@ public boolean isValid(UpdateResultsAPIObject updateResultsAPIObject, Constraint String kubeObjNameSpaceInKruizeObject = kruizeObject.getKubernetes_objects().get(0).getNamespace(); String kubeObjNameSpaceInResultsData = resultData.getKubernetes_objects().get(0).getNamespace(); - if (kruizeObject.getExperimentType().equals(AnalyzerConstants.ExperimentType.CONTAINER)) { + if (AnalyzerConstants.ExperimentBitMask.CONTAINER_BIT.isSet(kruizeObject.getExperimentType())) { if (kubeObjNameSpaceInKruizeObject != null && !kubeObjNameSpaceInKruizeObject.equals(kubeObjNameSpaceInResultsData)) { kubeObjsMisMatch = true; errorMsg = errorMsg.concat( diff --git a/src/main/java/com/autotune/analyzer/services/ListExperiments.java b/src/main/java/com/autotune/analyzer/services/ListExperiments.java index 7be49902a..820fd3cc5 100644 --- a/src/main/java/com/autotune/analyzer/services/ListExperiments.java +++ b/src/main/java/com/autotune/analyzer/services/ListExperiments.java @@ -17,6 +17,7 @@ package com.autotune.analyzer.services; import com.autotune.analyzer.adapters.DeviceDetailsAdapter; +import com.autotune.analyzer.adapters.KruizeObjectAdapter; import com.autotune.analyzer.adapters.RecommendationItemAdapter; import com.autotune.analyzer.experiment.KruizeExperiment; import com.autotune.analyzer.kruizeObject.KruizeObject; @@ -196,7 +197,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t } if (!error) { // create Gson Object - Gson gsonObj = createGsonObject(); + Gson gsonObj = createGsonObject(rmTable); // Modify the JSON response here based on query params. gsonStr = buildResponseBasedOnQuery(mKruizeExperimentMap, gsonObj, results, recommendations, latest, experimentName, rmTable); @@ -324,12 +325,41 @@ private void loadLMExperimentsFromDatabase(Map mKruizeExpe } } - private Gson createGsonObject() { + private Gson createGsonObject(boolean rmtable) { + if (!rmtable) { + return new GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .enableComplexMapKeySerialization() + .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) + .registerTypeAdapter(AnalyzerConstants.RecommendationItem.class, new RecommendationItemAdapter()) + .registerTypeAdapter(DeviceDetails.class, new DeviceDetailsAdapter()) + .setExclusionStrategies(new ExclusionStrategy() { + @Override + public boolean shouldSkipField(FieldAttributes f) { + return f.getDeclaringClass() == Metric.class && ( + f.getName().equals("trialSummaryResult") + || f.getName().equals("cycleDataMap") + ) || + f.getDeclaringClass() == ContainerData.class && ( + f.getName().equalsIgnoreCase("metrics") + ); + } + + @Override + public boolean shouldSkipClass(Class aClass) { + return false; + } + }) + .create(); + } + return new GsonBuilder() .disableHtmlEscaping() .setPrettyPrinting() .enableComplexMapKeySerialization() .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) + .registerTypeAdapter(KruizeObject.class, new KruizeObjectAdapter()) .registerTypeAdapter(AnalyzerConstants.RecommendationItem.class, new RecommendationItemAdapter()) .registerTypeAdapter(DeviceDetails.class, new DeviceDetailsAdapter()) .setExclusionStrategies(new ExclusionStrategy() { @@ -350,6 +380,7 @@ public boolean shouldSkipClass(Class aClass) { } }) .create(); + } private void checkPercentileInfo(Map mainKruizeExperimentMap) { diff --git a/src/main/java/com/autotune/database/helper/DBHelpers.java b/src/main/java/com/autotune/database/helper/DBHelpers.java index cde98d52c..da3e4faec 100644 --- a/src/main/java/com/autotune/database/helper/DBHelpers.java +++ b/src/main/java/com/autotune/database/helper/DBHelpers.java @@ -616,7 +616,9 @@ public static KruizeLMRecommendationEntry convertKruizeObjectTOLMRecommendation( kruizeRecommendationEntry.setVersion(KruizeConstants.KRUIZE_RECOMMENDATION_API_VERSION.LATEST.getVersionNumber()); kruizeRecommendationEntry.setExperiment_name(listRecommendationsAPIObject.getExperimentName()); kruizeRecommendationEntry.setCluster_name(listRecommendationsAPIObject.getClusterName()); - kruizeRecommendationEntry.setExperimentType(kruizeObject.getExperimentType().name()); + kruizeRecommendationEntry.setExperimentType( + ExperimentTypeUtil.getExperimentTypeFromBitMask(kruizeObject.getExperimentType()).name() + ); Timestamp endInterval = null; // todo : what happens if two k8 objects or Containers with different timestamp @@ -756,7 +758,9 @@ public static ListRecommendationsAPIObject getListRecommendationAPIObjectForDB(K listRecommendationsAPIObject.setClusterName(kruizeObject.getClusterName()); listRecommendationsAPIObject.setExperimentName(kruizeObject.getExperimentName()); listRecommendationsAPIObject.setKubernetesObjects(kubernetesAPIObjectList); - listRecommendationsAPIObject.setExperimentType(kruizeObject.getExperimentType()); + listRecommendationsAPIObject.setExperimentType( + ExperimentTypeUtil.getExperimentTypeFromBitMask(kruizeObject.getExperimentType()) + ); } return listRecommendationsAPIObject; }