Skip to content

Commit

Permalink
adding basic abstraction for updaters
Browse files Browse the repository at this point in the history
Signed-off-by: Shekhar Saxena <[email protected]>
  • Loading branch information
shekhar316 committed Dec 5, 2024
1 parent 5c2972d commit a46287c
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 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.
* 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.exceptions;

public class ApplyRecommendationsError extends Exception {
public ApplyRecommendationsError() {
}

public ApplyRecommendationsError(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 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.
* 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.exceptions;

public class InvalidRecommendationUpdaterType extends Exception {
public InvalidRecommendationUpdaterType() {
}

public InvalidRecommendationUpdaterType(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 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.
* 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.recommendations.updater;

import com.autotune.analyzer.exceptions.ApplyRecommendationsError;
import com.autotune.analyzer.exceptions.InvalidRecommendationUpdaterType;
import com.autotune.analyzer.kruizeObject.KruizeObject;

/**
* This interface defines the abstraction for updating resource recommendations in a system.
* Implementing classes will provide the logic to update resources with recommendations for a specific resources,
* such as CPU, memory, or any other resources that require periodic or dynamic adjustments.
*
* The RecommendationUpdater interface is designed to be extended by different updater classes.
* For example, vpaUpdaterImpl for updating resources with recommendations related to CPU and memory resources.
*/

public interface RecommendationUpdater {
/**
* Retrieves an instance of a specific updater implementation based on the provided updater type
*
* @param updaterType String the type of updater to retrieve
* @return RecommendationUpdaterImpl An instance of provided updater type class
* @throws InvalidRecommendationUpdaterType If the provided updater type doesn't match any valid type of updater.
*/
RecommendationUpdaterImpl getUpdaterInstance(String updaterType) throws InvalidRecommendationUpdaterType;

/**
* Checks whether the necessary updater dependencies are installed or available in the system.
*
* @return boolean true if the required updaters are installed, false otherwise.
*/
boolean isUpdaterInstalled();

/**
* Generates resource recommendations for a specific experiment based on the experiment's name.
*
* @param experimentName String The name of the experiment for which the resource recommendations should be generated.
* @return KruizeObject containing recommendations
*/
KruizeObject generateResourceRecommendationsForExperiment(String experimentName);

/**
* Applies the resource recommendations contained within the provided KruizeObject
* This method will take the KruizeObject, which contains the resource recommendations,
* and apply them to the desired resources.
*
* @param kruizeObject KruizeObject containing the resource recommendations to be applied.
* @throws ApplyRecommendationsError in case of any error.
*/
void applyResourceRecommendationsForExperiment(KruizeObject kruizeObject) throws ApplyRecommendationsError;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*******************************************************************************
* Copyright (c) 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.
* 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.recommendations.updater;

import com.autotune.analyzer.exceptions.ApplyRecommendationsError;
import com.autotune.analyzer.exceptions.FetchMetricsError;
import com.autotune.analyzer.exceptions.InvalidRecommendationUpdaterType;
import com.autotune.analyzer.kruizeObject.KruizeObject;
import com.autotune.analyzer.recommendations.engine.RecommendationEngine;
import com.autotune.analyzer.recommendations.updater.vpa.VpaUpdaterImpl;
import com.autotune.analyzer.utils.AnalyzerConstants;
import com.autotune.analyzer.utils.AnalyzerErrorConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RecommendationUpdaterImpl implements RecommendationUpdater {

private static final Logger LOGGER = LoggerFactory.getLogger(RecommendationUpdaterImpl.class);

/**
* Retrieves an instance of a specific updater implementation based on the provided updater type
*
* @param updaterType String the type of updater to retrieve
* @return RecommendationUpdaterImpl An instance of provided updater type class
* @throws InvalidRecommendationUpdaterType If the provided updater type doesn't match any valid type of updater.
*/
@Override
public RecommendationUpdaterImpl getUpdaterInstance(String updaterType) throws InvalidRecommendationUpdaterType {
if (AnalyzerConstants.RecommendationUpdaterConstants.SupportedUpdaters.VPA.equalsIgnoreCase(updaterType)) {
return VpaUpdaterImpl.getInstance();
} else {
throw new InvalidRecommendationUpdaterType(String.format(AnalyzerErrorConstants.RecommendationUpdaterErrors.UNSUPPORTED_UPDATER_TYPE, updaterType));
}
}

/**
* Checks whether the necessary updater dependencies are installed or available in the system.
* @return boolean true if the required updaters are installed, false otherwise.
*/
@Override
public boolean isUpdaterInstalled() {
/*
* This function will be implemented by specific updater type child classes
*/
return false;
}

/**
* Generates resource recommendations for a specific experiment based on the experiment's name.
*
* @param experimentName String The name of the experiment for which the resource recommendations should be generated.
* @return KruizeObject containing recommendations
*/
@Override
public KruizeObject generateResourceRecommendationsForExperiment(String experimentName) {
try {
LOGGER.info(AnalyzerConstants.RecommendationUpdaterConstants.InfoMsgs.GENERATING_RECOMMENDATIONS, experimentName);
// generating latest recommendations for experiment
RecommendationEngine recommendationEngine = new RecommendationEngine(experimentName, null, null);
int calCount = 0;
String validationMessage = recommendationEngine.validate_local();
if (validationMessage.isEmpty()) {
KruizeObject kruizeObject = recommendationEngine.prepareRecommendations(calCount);
if (kruizeObject.getValidation_data().isSuccess()) {
LOGGER.info(AnalyzerConstants.RecommendationUpdaterConstants.InfoMsgs.GENERATED_RECOMMENDATIONS, experimentName);
return kruizeObject;
} else {
throw new Exception(kruizeObject.getValidation_data().getMessage());
}
} else {
throw new Exception(validationMessage);
}
} catch (Exception | FetchMetricsError e) {
LOGGER.error(AnalyzerErrorConstants.RecommendationUpdaterErrors.GENERATE_RECOMMNEDATION_FAILED, experimentName);
LOGGER.debug(e.getMessage());
return null;
}
}

/**
* Applies the resource recommendations contained within the provided KruizeObject
* This method will take the KruizeObject, which contains the resource recommendations,
* and apply them to the desired resources.
*
* @param kruizeObject KruizeObject containing the resource recommendations to be applied.
* @throws ApplyRecommendationsError in case of any error.
*/
@Override
public void applyResourceRecommendationsForExperiment(KruizeObject kruizeObject) throws ApplyRecommendationsError {
/*
* This function will be implemented by specific updater type child classes
*/
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*******************************************************************************
* Copyright (c) 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.
* 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.recommendations.updater.vpa;

import com.autotune.analyzer.recommendations.updater.RecommendationUpdaterImpl;
import com.autotune.analyzer.utils.AnalyzerConstants;
import com.autotune.analyzer.utils.AnalyzerErrorConstants;
import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionList;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.ApiextensionsAPIGroupDSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class VpaUpdaterImpl extends RecommendationUpdaterImpl {
private static final Logger LOGGER = LoggerFactory.getLogger(VpaUpdaterImpl.class);
private static VpaUpdaterImpl vpaUpdater = new VpaUpdaterImpl();

private KubernetesClient kubernetesClient;
private ApiextensionsAPIGroupDSL apiextensionsClient;


private VpaUpdaterImpl() {
this.kubernetesClient = new DefaultKubernetesClient();
this.apiextensionsClient = kubernetesClient.apiextensions();
}

public static VpaUpdaterImpl getInstance() {
if (vpaUpdater == null) {
vpaUpdater = new VpaUpdaterImpl();
}
return vpaUpdater;
}

/**
* Checks whether the necessary updater dependencies are installed or available in the system.
* @return boolean true if the required updaters are installed, false otherwise.
*/
@Override
public boolean isUpdaterInstalled() {
LOGGER.info(AnalyzerConstants.RecommendationUpdaterConstants.InfoMsgs.CHECKING_IF_UPDATER_INSTALLED,
AnalyzerConstants.RecommendationUpdaterConstants.SupportedUpdaters.VPA);
// checking if VPA CRD is present or not
CustomResourceDefinitionList crdList = apiextensionsClient.v1().customResourceDefinitions().list();
boolean isVpaInstalled = crdList.getItems().stream().anyMatch(crd -> AnalyzerConstants.RecommendationUpdaterConstants.VPA.VPA_PLURAL.equalsIgnoreCase(crd.getSpec().getNames().getKind()));
if (isVpaInstalled) {
LOGGER.info(AnalyzerConstants.RecommendationUpdaterConstants.InfoMsgs.FOUND_UPDATER_INSTALLED, AnalyzerConstants.RecommendationUpdaterConstants.SupportedUpdaters.VPA);
} else {
LOGGER.error(AnalyzerErrorConstants.RecommendationUpdaterErrors.UPDATER_NOT_INSTALLED, AnalyzerConstants.RecommendationUpdaterConstants.SupportedUpdaters.VPA);
}
return isVpaInstalled;
}
}
33 changes: 33 additions & 0 deletions src/main/java/com/autotune/analyzer/utils/AnalyzerConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -666,4 +666,37 @@ private APIVersionConstants() {
}
}
}

public static final class RecommendationUpdaterConstants {
private RecommendationUpdaterConstants() {

}

public static final class SupportedUpdaters {
public static final String VPA = "vpa";

private SupportedUpdaters() {

}
}

public static final class VPA {
public static final String VPA_PLURAL = "VerticalPodAutoscaler";

private VPA() {

}
}

public static final class InfoMsgs {
public static final String GENERATING_RECOMMENDATIONS = "Generating recommendations for experiment: {}";
public static final String GENERATED_RECOMMENDATIONS = "Generated recommendations for experiment: {}";
public static final String CHECKING_IF_UPDATER_INSTALLED = "Verifying if the updater is installed: {}";
public static final String FOUND_UPDATER_INSTALLED = "Found updater is installed: {}";

private InfoMsgs() {

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -286,4 +286,14 @@ private KruizeRecommendationError() {
}
}
}

public static final class RecommendationUpdaterErrors {
private RecommendationUpdaterErrors() {

}

public static final String UNSUPPORTED_UPDATER_TYPE = "Updater type %s is not supported.";
public static final String GENERATE_RECOMMNEDATION_FAILED = "Failed to generate recommendations for experiment: {}";
public static final String UPDATER_NOT_INSTALLED = "Updater is not installed: {}";
}
}

0 comments on commit a46287c

Please sign in to comment.