package com.sequenceiq.cloudbreak.shell.commands.common;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import com.fasterxml.jackson.databind.JsonNode;
import com.sequenceiq.cloudbreak.api.model.BlueprintRequest;
import com.sequenceiq.cloudbreak.api.model.BlueprintResponse;
import com.sequenceiq.cloudbreak.shell.commands.BaseCommands;
import com.sequenceiq.cloudbreak.shell.model.Hints;
import com.sequenceiq.cloudbreak.shell.model.OutPutType;
import com.sequenceiq.cloudbreak.shell.model.ShellContext;
public class BlueprintCommands implements BaseCommands {
private ShellContext shellContext;
public BlueprintCommands(ShellContext shellContext) {
this.shellContext = shellContext;
}
@CliAvailabilityIndicator(value = "blueprint create")
public boolean createAvailable() {
return true;
}
@CliCommand(value = "blueprint create", help = "Add a new blueprint with either --url or --file")
public String create(
@CliOption(key = "name", mandatory = true, help = "Name of the blueprint to download from") String name,
@CliOption(key = "description", help = "Description of the blueprint to download from") String description,
@CliOption(key = "url", help = "URL of the blueprint to download from") String url,
@CliOption(key = "file", help = "File which contains the blueprint") File file,
@CliOption(key = "publicInAccount", help = "flags if the blueprint is public in the account",
unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") boolean publicInAccount) {
try {
String message;
String json = file == null ? IOUtils.toString(new URL(url)) : IOUtils.toString(new FileInputStream(file));
if (json != null) {
BlueprintRequest blueprintRequest = new BlueprintRequest();
blueprintRequest.setName(name);
blueprintRequest.setDescription(description);
blueprintRequest.setAmbariBlueprint(shellContext.objectMapper().readValue(json, JsonNode.class));
String id;
if (publicInAccount) {
id = shellContext.cloudbreakClient().blueprintEndpoint().postPublic(blueprintRequest).getId().toString();
} else {
id = shellContext.cloudbreakClient().blueprintEndpoint().postPrivate(blueprintRequest).getId().toString();
}
shellContext.addBlueprint(id);
if (shellContext.cloudbreakClient().blueprintEndpoint().getPublics().isEmpty()) {
if (shellContext.isMarathonMode()) {
shellContext.setHint(Hints.CONFIGURE_MARATHON_HOSTGROUP);
} else if (shellContext.isYarnMode()) {
shellContext.setHint(Hints.CONFIGURE_YARN_HOSTGROUP);
} else {
shellContext.setHint(Hints.CONFIGURE_INSTANCEGROUP);
}
} else {
if (shellContext.isMarathonMode()) {
shellContext.setHint(Hints.CONFIGURE_MARATHON_HOSTGROUP);
} else if (shellContext.isYarnMode()) {
shellContext.setHint(Hints.CONFIGURE_YARN_HOSTGROUP);
} else {
shellContext.setHint(Hints.SELECT_STACK);
}
}
message = String.format("Blueprint created with id: '%s' and name: '%s'", id, name);
} else {
message = "No blueprint specified";
}
return message;
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@Override
@CliAvailabilityIndicator(value = "blueprint list")
public boolean listAvailable() {
return true;
}
@Override
@CliCommand(value = "blueprint list", help = "Shows the currently available blueprints")
public String list() throws Exception {
try {
Set<BlueprintResponse> publics = shellContext.cloudbreakClient().blueprintEndpoint().getPublics();
return shellContext.outputTransformer().render(shellContext.responseTransformer().transformToMap(publics, "id", "name"), "ID", "INFO");
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@Override
@CliAvailabilityIndicator(value = { "blueprint select --id", "blueprint select --name" })
public boolean selectAvailable() {
return shellContext.isBlueprintAccessible();
}
@Override
public String select(Long id, String name) {
try {
if (id != null) {
if (shellContext.cloudbreakClient().blueprintEndpoint().get(id) != null) {
shellContext.addBlueprint(id.toString());
shellContext.resetMarathonHostGroups();
shellContext.resetYarnHostGroups();
if (shellContext.isMarathonMode()) {
shellContext.setHint(Hints.CONFIGURE_MARATHON_HOSTGROUP);
} else if (shellContext.isYarnMode()) {
shellContext.setHint(Hints.CONFIGURE_YARN_HOSTGROUP);
} else if (shellContext.getStackId() != null) {
shellContext.setHint(Hints.CONFIGURE_HOSTGROUP);
} else {
shellContext.setHint(Hints.CONFIGURE_INSTANCEGROUP);
}
return String.format("Blueprint has been selected, id: %s", id);
}
} else if (name != null) {
BlueprintResponse blueprint = shellContext.cloudbreakClient().blueprintEndpoint().getPublic(name);
if (blueprint != null) {
shellContext.addBlueprint(blueprint.getId().toString());
shellContext.resetMarathonHostGroups();
shellContext.resetYarnHostGroups();
if (shellContext.isMarathonMode()) {
shellContext.setHint(Hints.CONFIGURE_MARATHON_HOSTGROUP);
} else if (shellContext.isYarnMode()) {
shellContext.setHint(Hints.CONFIGURE_YARN_HOSTGROUP);
} else if (shellContext.getStackId() != null) {
shellContext.setHint(Hints.CONFIGURE_HOSTGROUP);
} else {
shellContext.setHint(Hints.CONFIGURE_INSTANCEGROUP);
}
return String.format("Blueprint has been selected, name: %s", name);
}
}
return "No blueprint specified (select a blueprint by --id or --name)";
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@CliCommand(value = "blueprint select --id", help = "Select the blueprint by its id")
@Override
public String selectById(@CliOption(key = "", mandatory = true) Long id) throws Exception {
return select(id, null);
}
@CliCommand(value = "blueprint select --name", help = "Select the blueprint by its name")
@Override
public String selectByName(@CliOption(key = "", mandatory = true) String name) throws Exception {
return select(null, name);
}
@Override
@CliAvailabilityIndicator(value = { "blueprint show --id", "blueprint show --name" })
public boolean showAvailable() {
return true;
}
@Override
public String show(Long id, String name, OutPutType outPutType) {
try {
outPutType = outPutType == null ? OutPutType.RAW : outPutType;
BlueprintResponse blueprintResponse;
if (id != null) {
blueprintResponse = shellContext.cloudbreakClient().blueprintEndpoint().get(id);
} else if (name != null) {
blueprintResponse = shellContext.cloudbreakClient().blueprintEndpoint().getPublic(name);
} else {
throw shellContext.exceptionTransformer().transformToRuntimeException("No blueprints specified");
}
return shellContext.outputTransformer().render(outPutType,
shellContext.responseTransformer().transformObjectToStringMap(blueprintResponse, "ambariBlueprint"), "FIELD", "INFO")
+ "\n\n"
+ shellContext.outputTransformer().render(outPutType,
getComponentMap(blueprintResponse.getAmbariBlueprint()), "HOSTGROUP", "COMPONENT");
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@CliCommand(value = "blueprint show --id", help = "Show the blueprint 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 = "blueprint show --name", help = "Show the blueprint 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);
}
@Override
@CliAvailabilityIndicator(value = { "blueprint delete --id", "blueprint delete --name" })
public boolean deleteAvailable() {
return true;
}
@Override
public String delete(Long id, String name) throws Exception {
try {
if (id != null) {
shellContext.cloudbreakClient().blueprintEndpoint().delete(id);
return String.format("Blueprint deleted with %s id", id);
} else if (name != null) {
shellContext.cloudbreakClient().blueprintEndpoint().deletePublic(name);
return String.format("Blueprint deleted with %s name", name);
} else {
throw shellContext.exceptionTransformer().transformToRuntimeException("No blueprint specified (select a blueprint by --id or --name)");
}
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException(ex);
}
}
@CliCommand(value = "blueprint delete --id", help = "Delete the blueprint by its id")
@Override
public String deleteById(@CliOption(key = "", mandatory = true) Long id) throws Exception {
return delete(id, null);
}
@CliCommand(value = "blueprint delete --name", help = "Delete the blueprint by its name")
@Override
public String deleteByName(@CliOption(key = "", mandatory = true) String name) throws Exception {
return delete(null, name);
}
@CliAvailabilityIndicator(value = "blueprint defaults")
public boolean defaultAvailable() {
return true;
}
@CliCommand(value = "blueprint defaults", help = "Adds the default blueprints to Ambari")
public String defaults() {
String message = "Default blueprints added";
try {
shellContext.cloudbreakClient().blueprintEndpoint().getPublics();
} catch (Exception ex) {
throw shellContext.exceptionTransformer().transformToRuntimeException("Failed to add the default blueprints: " + ex.getMessage());
}
return message;
}
@Override
public ShellContext shellContext() {
return shellContext;
}
private Map<String, List<String>> getComponentMap(String json) {
Map<String, List<String>> map = new HashMap<>();
try {
JsonNode hostGroups = shellContext.objectMapper().readTree(json.getBytes()).get("host_groups");
for (JsonNode hostGroup : hostGroups) {
List<String> components = new ArrayList<>();
JsonNode componentsNodes = hostGroup.get("components");
for (JsonNode componentsNode : componentsNodes) {
components.add(componentsNode.get("name").asText());
}
map.put(hostGroup.get("name").asText(), components);
}
} catch (IOException e) {
map = new HashMap<>();
}
return map;
}
}