package com.sequenceiq.cloudbreak.shell.commands.common;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.http.MethodNotSupportedException;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import com.sequenceiq.cloudbreak.api.model.RecipeRequest;
import com.sequenceiq.cloudbreak.api.model.RecipeResponse;
import com.sequenceiq.cloudbreak.common.type.RecipeType;
import com.sequenceiq.cloudbreak.shell.commands.BaseCommands;
import com.sequenceiq.cloudbreak.shell.model.OutPutType;
import com.sequenceiq.cloudbreak.shell.model.ShellContext;
public class RecipeCommands implements BaseCommands {
private static final String CREATE_SUCCESS_MESSAGE = "Recipe created with id: %s and name: '%s'";
private ShellContext shellContext;
public RecipeCommands(ShellContext shellContext) {
this.shellContext = shellContext;
}
@CliAvailabilityIndicator(value = "recipe list")
@Override
public boolean listAvailable() {
return !shellContext.isMarathonMode() && !shellContext.isYarnMode();
}
@CliCommand(value = "recipe list", help = "Shows the currently available recipes")
@Override
public String list() {
try {
Set<RecipeResponse> publics = shellContext.cloudbreakClient().recipeEndpoint().getPublics();
return shellContext.outputTransformer().render(shellContext.responseTransformer().transformToMap(publics, "id", "name"), "ID", "INFO");
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@Override
public boolean selectAvailable() {
return false;
}
@Override
public String select(Long id, String name) throws Exception {
throw new MethodNotSupportedException("Recipe select command not supported");
}
@Override
public String selectById(Long id) throws Exception {
return select(id, null);
}
@Override
public String selectByName(String name) throws Exception {
return select(null, name);
}
@CliAvailabilityIndicator("recipe create")
public boolean createAvailable() {
return !shellContext.isMarathonMode() && !shellContext.isYarnMode();
}
@CliCommand(value = "recipe create", help = "Creates a new recipe")
public String createRecipe(
@CliOption(key = "name", mandatory = true, help = "Unique name of the recepie") String name,
@CliOption(key = "type", mandatory = true, help = "Type of recipe") RecipeType recipeType,
@CliOption(key = "description", help = "Description of the recepie") String description,
@CliOption(key = "scriptFile", help = "Path of the script file") File scriptFile,
@CliOption(key = "scriptUrl", help = "URL for the script") String scriptUrl,
@CliOption(key = "publicInAccount", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true",
help = "flags if the recipe is public in the account") Boolean publicInAccount) {
if (scriptFile != null && !scriptFile.exists()) {
throw shellContext.exceptionTransformer().transformToRuntimeException("Recipe file not exists");
} else if (scriptFile != null && scriptUrl != null) {
throw shellContext.exceptionTransformer().transformToRuntimeException("Either the file or the url can be provided for recipe");
} else if (scriptFile == null && scriptUrl == null) {
throw shellContext.exceptionTransformer().transformToRuntimeException("File or the url must be provided for recipe");
}
try {
RecipeRequest recipeRequest = new RecipeRequest();
recipeRequest.setRecipeType(recipeType);
recipeRequest.setName(name);
recipeRequest.setDescription(description);
recipeRequest.setUri(scriptUrl);
if (scriptFile != null) {
String script = IOUtils.toString(new FileInputStream(scriptFile));
String encodedContent = Base64.encodeBase64String(script.getBytes());
recipeRequest.setContent(encodedContent);
}
Long id;
if (publicInAccount) {
id = shellContext.cloudbreakClient().recipeEndpoint().postPublic(recipeRequest).getId();
} else {
id = shellContext.cloudbreakClient().recipeEndpoint().postPrivate(recipeRequest).getId();
}
return String.format(CREATE_SUCCESS_MESSAGE, id, recipeRequest.getName());
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@CliAvailabilityIndicator(value = {"recipe show --id", "recipe show --name"})
@Override
public boolean showAvailable() {
return !shellContext.isMarathonMode() && !shellContext.isYarnMode();
}
@Override
public String show(Long id, String name, OutPutType outPutType) {
try {
outPutType = outPutType == null ? OutPutType.RAW : outPutType;
RecipeResponse recipeMap;
if (id != null) {
recipeMap = shellContext.cloudbreakClient().recipeEndpoint().get(id);
} else if (name != null) {
recipeMap = shellContext.cloudbreakClient().recipeEndpoint().getPublic(name);
} else {
throw shellContext.exceptionTransformer().transformToRuntimeException("Recipe not specified");
}
Map<String, String> map = new HashMap<>();
map.put("id", recipeMap.getId().toString());
map.put("name", recipeMap.getName());
map.put("description", recipeMap.getDescription());
return shellContext.outputTransformer().render(outPutType, map, "FIELD", "INFO");
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@CliCommand(value = "recipe show --id", help = "Show the recipe by its id")
@Override
public String showById(
@CliOption(key = "", mandatory = true) Long id,
@CliOption(key = "outputType", help = "OutputType of the response") OutPutType outPutType) throws Exception {
return show(id, null, outPutType);
}
@CliCommand(value = "recipe show --name", help = "Show the recipe by its name")
@Override
public String showByName(
@CliOption(key = "", mandatory = true) String name,
@CliOption(key = "outputType", help = "OutputType of the response") OutPutType outPutType) throws Exception {
return show(null, name, outPutType);
}
@CliAvailabilityIndicator(value = {"recipe delete --id", "recipe delete --name"})
@Override
public boolean deleteAvailable() {
return !shellContext.isMarathonMode() && !shellContext.isYarnMode();
}
@Override
public String delete(Long id, String name) {
try {
if (id != null) {
shellContext.cloudbreakClient().recipeEndpoint().delete(id);
return String.format("Recipe deleted with %s id", id);
} else if (name != null) {
shellContext.cloudbreakClient().recipeEndpoint().deletePublic(name);
return String.format("Recipe deleted with %s name", name);
}
throw shellContext.exceptionTransformer().transformToRuntimeException("Recipe not specified (select recipe by --id or --name)");
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@CliCommand(value = "recipe delete --id", help = "Delete the recipe by its id")
@Override
public String deleteById(@CliOption(key = "", mandatory = true) Long id) throws Exception {
return delete(id, null);
}
@CliCommand(value = "recipe delete --name", help = "Delete the recipe by its name")
@Override
public String deleteByName(@CliOption(key = "", mandatory = true) String name) throws Exception {
return delete(null, name);
}
@Override
public ShellContext shellContext() {
return shellContext;
}
}