/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ambari.shell.commands;
import static org.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import org.apache.ambari.groovy.client.AmbariClient;
import org.apache.ambari.shell.completion.Blueprint;
import org.apache.ambari.shell.model.AmbariContext;
import org.apache.ambari.shell.model.Hints;
import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.stereotype.Component;
/**
* Blueprint related commands used in the shell.
*
* @see org.apache.ambari.groovy.client.AmbariClient
*/
@Component
public class BlueprintCommands implements CommandMarker {
private AmbariClient client;
private AmbariContext context;
private ObjectMapper jsonMapper;
@Autowired
public BlueprintCommands(AmbariClient client, AmbariContext context, ObjectMapper jsonMapper) {
this.client = client;
this.context = context;
this.jsonMapper = jsonMapper;
}
/**
* Checks whether the blueprints command is available or not.
*
* @return true if available false otherwise
*/
@CliAvailabilityIndicator("blueprint list")
public boolean isBlueprintListCommandAvailable() {
return context.areBlueprintsAvailable();
}
/**
* Prints all the blueprints.
*
* @return list of blueprints
*/
@CliCommand(value = "blueprint list", help = "Lists all known blueprints")
public String listBlueprints() {
return renderSingleMap(client.getBlueprintsMap(), "BLUEPRINT", "STACK");
}
/**
* Checks whether the blueprint show command is available or not.
*
* @return true if available false otherwise
*/
@CliAvailabilityIndicator(value = "blueprint show")
public boolean isBlueprintShowCommandAvailable() {
return context.areBlueprintsAvailable();
}
/**
* Shows the requested blueprint's details.
*
* @param id id of the blueprint
* @return blueprint as formatted table
*/
@CliCommand(value = "blueprint show", help = "Shows the blueprint by its id")
public String showBlueprint(
@CliOption(key = "id", mandatory = true, help = "Id of the blueprint") Blueprint id) {
return renderMultiValueMap(client.getBlueprintMap(id.getName()), "HOSTGROUP", "COMPONENT");
}
/**
* Checks whether the blueprint add command is available or not.
*
* @return true if available false otherwise
*/
@CliAvailabilityIndicator(value = "blueprint add")
public boolean isBlueprintAddCommandAvailable() {
return true;
}
/**
* Adds a blueprint to the Ambari server either through an URL or from a file.
* If both specified the file takes precedence.
*
* @param url -optional, URL containing the blueprint json
* @param file - optional, file containing the blueprint json
* @return status message
*/
@CliCommand(value = "blueprint add", help = "Add a new blueprint with either --url or --file")
public String addBlueprint(
@CliOption(key = "url", mandatory = false, help = "URL of the blueprint to download from") String url,
@CliOption(key = "file", mandatory = false, help = "File which contains the blueprint") File file) {
String message;
try {
String json = file == null ? readContent(url) : readContent(file);
if (json != null) {
client.addBlueprint(json);
context.setHint(Hints.BUILD_CLUSTER);
context.setBlueprintsAvailable(true);
message = String.format("Blueprint: '%s' has been added", getBlueprintName(json));
} else {
message = "No blueprint specified";
}
} catch (Exception e) {
message = "Cannot add blueprint: " + e.getMessage();
}
return message;
}
/**
* Checks whether the blueprint defaults command is available or not.
*
* @return true if available false otherwise
*/
@CliAvailabilityIndicator(value = "blueprint defaults")
public boolean isBlueprintDefaultsAddCommandAvailable() {
return !context.areBlueprintsAvailable();
}
/**
* Adds two default blueprints to the Ambari server.
*
* @return status message
*/
@CliCommand(value = "blueprint defaults", help = "Adds the default blueprints to Ambari")
public String addBlueprint() {
String message = "Default blueprints added";
try {
client.addDefaultBlueprints();
context.setHint(Hints.BUILD_CLUSTER);
context.setBlueprintsAvailable(true);
} catch (Exception e) {
message = "Failed to add the default blueprints: " + e.getMessage();
}
return message;
}
private String readContent(File file) {
String content = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
content = IOUtils.toString(fis);
} catch (IOException e) {
// not important
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException ex) {
}
}
}
return content;
}
private String readContent(String url) {
String content = null;
try {
content = IOUtils.toString(new URL(url));
} catch (IOException e) {
// not important
}
return content;
}
private String getBlueprintName(String json) {
String result = "";
try {
result = jsonMapper.readTree(json.getBytes()).get("Blueprints").get("blueprint_name").asText();
} catch (IOException e) {
// not important
}
return result;
}
}