/*****************************************************************************
* Copyright (c) 2012-2015 VMware, Inc. All Rights Reserved.
* 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.vmware.bdd.cli.commands;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import jline.console.ConsoleReader;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
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;
import com.vmware.bdd.apitypes.AppManagerRead;
import com.vmware.bdd.apitypes.ClusterCreate;
import com.vmware.bdd.apitypes.ClusterRead;
import com.vmware.bdd.apitypes.ClusterType;
import com.vmware.bdd.apitypes.DistroRead;
import com.vmware.bdd.apitypes.ElasticityRequestBody;
import com.vmware.bdd.apitypes.ElasticityRequestBody.ElasticityMode;
import com.vmware.bdd.apitypes.FixDiskRequestBody;
import com.vmware.bdd.apitypes.NetConfigInfo.NetTrafficType;
import com.vmware.bdd.apitypes.NetworkRead;
import com.vmware.bdd.apitypes.NodeGroupAdd;
import com.vmware.bdd.apitypes.NodeGroupCreate;
import com.vmware.bdd.apitypes.NodeGroupRead;
import com.vmware.bdd.apitypes.NodeRead;
import com.vmware.bdd.apitypes.Priority;
import com.vmware.bdd.apitypes.ResourceScale;
import com.vmware.bdd.apitypes.TaskRead;
import com.vmware.bdd.apitypes.TaskRead.NodeStatus;
import com.vmware.bdd.apitypes.TopologyType;
import com.vmware.bdd.apitypes.VcResourceMap;
import com.vmware.bdd.cli.rest.AppManagerRestClient;
import com.vmware.bdd.cli.rest.CliRestException;
import com.vmware.bdd.cli.rest.ClusterRestClient;
import com.vmware.bdd.cli.rest.NetworkRestClient;
import com.vmware.bdd.exception.WarningMessageException;
import com.vmware.bdd.usermgmt.UserMgmtConstants;
import com.vmware.bdd.utils.AppConfigValidationUtils;
import com.vmware.bdd.utils.AppConfigValidationUtils.ValidationType;
import com.vmware.bdd.utils.CommonUtil;
import com.vmware.bdd.utils.ListToStringConverter;
import com.vmware.bdd.utils.ValidateResult;
@Component
public class ClusterCommands implements CommandMarker {
private static LinkedHashMap<String, List<String>> USER_MGMT_COLUMN_FORMAT = null;
@Autowired
private NetworkRestClient networkRestClient;
@Autowired
private ClusterRestClient restClient;
@Autowired
private AppManagerRestClient appManagerRestClient;
@CliAvailabilityIndicator({ "cluster help" })
public boolean isCommandAvailable() {
return true;
}
@CliCommand(value = "cluster create", help = "Create a new cluster")
public void createCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String name,
@CliOption(key = { "appManager" }, mandatory = false, help = "The application manager name") final String appManager,
@CliOption(key = { "type" }, mandatory = false, help = "The cluster type is Hadoop or HBase") final String type,
@CliOption(key = { "distro" }, mandatory = false, help = "The distro name") final String distro,
@CliOption(key = { "specFile" }, mandatory = false, help = "The spec file name path") final String specFilePath,
@CliOption(key = { "rpNames" }, mandatory = false, help = "Resource Pools for the cluster: use \",\" among names.") final String rpNames,
@CliOption(key = { "dsNames" }, mandatory = false, help = "Datastores for the cluster: use \",\" among names.") final String dsNames,
@CliOption(key = { "networkName" }, mandatory = false, help = "Network Name used for management") final String networkName,
@CliOption(key = { "hdfsNetworkName" }, mandatory = false, help = "Network Name for HDFS traffic.") final String hdfsNetworkName,
@CliOption(key = { "mapredNetworkName" }, mandatory = false, help = "Network Name for MapReduce traffic") final String mapredNetworkName,
@CliOption(key = { "topology" }, mandatory = false, help = "You must specify the topology type: HVE or RACK_AS_RACK or HOST_AS_RACK") final String topology,
@CliOption(key = { "resume" }, mandatory = false, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = "flag to resume cluster creation") final boolean resume,
@CliOption(key = { "skipConfigValidation" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Skip cluster configuration validation. ") final boolean skipConfigValidation,
@CliOption(key = { "yes" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Answer 'yes' to all Y/N questions. ") final boolean alwaysAnswerYes,
@CliOption(key = { "password" }, mandatory = false, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = "Answer 'yes' to set password for all VMs in this cluster.") final boolean setClusterPassword,
@CliOption(key = { "localRepoURL" }, mandatory = false, help = "Local yum server URL for application managers, ClouderaManager/Ambari.") final String localRepoURL,
@CliOption(key = { "adminGroupName" }, mandatory = false, help = "AD/LDAP Admin Group Name.") final String adminGroupName,
@CliOption(key = { "userGroupName" }, mandatory = false, help = "AD/LDAP User Group Name.") final String userGroupName,
@CliOption(key = { "disableLocalUsers" }, mandatory = false, help = "Disable local users") final Boolean disableLocalUsersFlag,
@CliOption(key = { "skipVcRefresh" }, mandatory = false, help = "flag to skip refreshing VC resources") final Boolean skipVcRefresh,
@CliOption(key = { "template" }, mandatory = false, help = "The node template name") final String templateName
) {
// validate the name
if (name.indexOf("-") != -1) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_CLUSTER + Constants.PARAM_NOT_CONTAIN_HORIZONTAL_LINE);
return;
} else if (name.indexOf(" ") != -1) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_CLUSTER + Constants.PARAM_NOT_CONTAIN_BLANK_SPACE);
return;
}
// process resume
if (resume && setClusterPassword) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.RESUME_DONOT_NEED_SET_PASSWORD);
return;
} else if (resume) {
resumeCreateCluster(name, skipVcRefresh);
return;
}
// build ClusterCreate object
ClusterCreate clusterCreate = new ClusterCreate();
clusterCreate.setName(name);
if (!CommandsUtils.isBlank(appManager)
&& !Constants.IRONFAN.equalsIgnoreCase(appManager)) {
AppManagerRead appManagerRead = appManagerRestClient.get(appManager);
if (appManagerRead == null) {
CommandsUtils
.printCmdFailure(
Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE,
Constants.OUTPUT_OP_RESULT_FAIL,
appManager + " cannot be found in the list of application managers.");
return;
}
}
if (CommandsUtils.isBlank(appManager)) {
clusterCreate.setAppManager(Constants.IRONFAN);
} else {
clusterCreate.setAppManager(appManager);
// local yum repo url for 3rd party app managers like ClouderaMgr, Ambari etc.
if (!CommandsUtils.isBlank(localRepoURL)) {
clusterCreate.setLocalRepoURL(localRepoURL);
}
}
if (setClusterPassword) {
String password = getPassword();
//user would like to set password, but failed to enter
//a valid one, quit cluster create
if (password == null) {
return;
} else {
clusterCreate.setPassword(password);
}
}
if (type != null) {
ClusterType clusterType = ClusterType.getByDescription(type);
if (clusterType == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE,
Constants.OUTPUT_OP_RESULT_FAIL, Constants.INVALID_VALUE + " " + "type=" + type);
return;
}
clusterCreate.setType(clusterType);
} else if (specFilePath == null) {
// create Hadoop (HDFS + MapReduce) cluster as default
clusterCreate.setType(ClusterType.HDFS_MAPRED);
}
TopologyType policy = null;
if (topology != null) {
policy = validateTopologyValue(name, topology);
if (policy == null) {
return;
}
} else {
policy = TopologyType.NONE;
}
clusterCreate.setTopologyPolicy(policy);
DistroRead distroRead4Create;
try {
if (distro != null) {
DistroRead[] distroReads =
appManagerRestClient
.getDistros(clusterCreate.getAppManager());
distroRead4Create = getDistroByName(distroReads, distro);
if (distroRead4Create == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE,
Constants.OUTPUT_OP_RESULT_FAIL, Constants.PARAM_DISTRO +
Constants.PARAM_NOT_SUPPORTED + getDistroNames(distroReads));
return;
}
} else {
distroRead4Create =
appManagerRestClient.getDefaultDistro(clusterCreate
.getAppManager());
if (distroRead4Create == null
|| CommandsUtils.isBlank(distroRead4Create.getName())) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE,
Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_NO_DEFAULT_DISTRO);
return;
}
}
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
e.getMessage());
return;
}
Map<String, Map<String, String>> infraConfigs = new HashMap<String, Map<String, String>>();
if(StringUtils.isBlank(adminGroupName) && StringUtils.isBlank(userGroupName)) {
//both adminGroupName and userGroupName are null, supposes no need to enable ldap.
} else if(!StringUtils.isBlank(adminGroupName) && !StringUtils.isBlank(userGroupName)) {
if (MapUtils.isEmpty(infraConfigs.get(UserMgmtConstants.LDAP_USER_MANAGEMENT))) {
initInfraConfigs(infraConfigs, disableLocalUsersFlag);
}
Map<String, String> userMgmtConfig = infraConfigs.get(UserMgmtConstants.LDAP_USER_MANAGEMENT);
userMgmtConfig.put(UserMgmtConstants.ADMIN_GROUP_NAME, adminGroupName);
userMgmtConfig.put(UserMgmtConstants.USER_GROUP_NAME, userGroupName);
clusterCreate.setInfrastructure_config(infraConfigs);
} else {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
"You need to supply both AdminGroupName and UserGroupName.");
return;
}
clusterCreate.setDistro(distroRead4Create.getName());
clusterCreate.setDistroVendor(distroRead4Create.getVendor());
clusterCreate.setDistroVersion(distroRead4Create.getVersion());
clusterCreate.setTemplateName(templateName);
if (rpNames != null) {
List<String> rpNamesList = CommandsUtils.inputsConvert(rpNames);
if (rpNamesList.isEmpty()) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE,
Constants.OUTPUT_OP_RESULT_FAIL,
Constants.INPUT_RPNAMES_PARAM + Constants.MULTI_INPUTS_CHECK);
return;
} else {
clusterCreate.setRpNames(rpNamesList);
}
}
if (dsNames != null) {
List<String> dsNamesList = CommandsUtils.inputsConvert(dsNames);
if (dsNamesList.isEmpty()) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE,
Constants.OUTPUT_OP_RESULT_FAIL,
Constants.INPUT_DSNAMES_PARAM + Constants.MULTI_INPUTS_CHECK);
return;
} else {
clusterCreate.setDsNames(dsNamesList);
}
}
List<String> failedMsgList = new ArrayList<String>();
List<String> warningMsgList = new ArrayList<String>();
Set<String> allNetworkNames = new HashSet<String>();
try {
if (specFilePath != null) {
ClusterCreate clusterSpec =
CommandsUtils.getObjectByJsonString(ClusterCreate.class,
CommandsUtils.dataFromFile(specFilePath));
clusterCreate.setSpecFile(true);
clusterCreate.setExternalHDFS(clusterSpec.getExternalHDFS());
clusterCreate.setExternalMapReduce(clusterSpec.getExternalMapReduce());
clusterCreate.setExternalNamenode(clusterSpec.getExternalNamenode());
clusterCreate.setExternalSecondaryNamenode(clusterSpec.getExternalSecondaryNamenode());
clusterCreate.setExternalDatanodes(clusterSpec.getExternalDatanodes());
clusterCreate.setNodeGroups(clusterSpec.getNodeGroups());
clusterCreate.setConfiguration(clusterSpec.getConfiguration());
// TODO: W'd better merge validateConfiguration with validateClusterSpec to avoid repeated validation.
if (CommandsUtils.isBlank(appManager)
|| Constants.IRONFAN.equalsIgnoreCase(appManager)) {
validateConfiguration(clusterCreate, skipConfigValidation,
warningMsgList, failedMsgList);
}
clusterCreate.validateNodeGroupNames();
if (!validateHAInfo(clusterCreate.getNodeGroups())) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE,
Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_CLUSTER_SPEC_HA_ERROR + specFilePath);
return;
}
Map<String, Map<String, String>> specInfraConfigs = clusterSpec.getInfrastructure_config();
if(!MapUtils.isEmpty(specInfraConfigs)) //spec infra config is not empty
{
if(MapUtils.isNotEmpty(infraConfigs)) {
System.out.println("adminGroup and userGroup has been specified as commandline parameters, so the values inside spec file will be ignored.");
} else {
clusterCreate.setInfrastructure_config(specInfraConfigs);
}
}
Map<String, Object> configuration = clusterSpec.getConfiguration();
if (MapUtils.isNotEmpty(configuration)) {
Map<String, Map<String, String>> serviceUserConfig = (Map<String, Map<String, String>>)configuration.get(UserMgmtConstants.SERVICE_USER_CONFIG_IN_SPEC_FILE);
if (MapUtils.isNotEmpty(serviceUserConfig)) {
//user didn't specify ldap in command line and specfile, but specfiy ldap user in service user
if (hasLdapServiceUser(serviceUserConfig) && (clusterCreate.getInfrastructure_config() == null)) {
Map<String, Map<String, String>> infraConfig = new HashMap<>();
initInfraConfigs(infraConfig, disableLocalUsersFlag);
clusterCreate.setInfrastructure_config(infraConfig);
}
validateServiceUserConfigs(appManager, clusterSpec, failedMsgList);
}
}
}
allNetworkNames = getAllNetworkNames();
} catch (Exception e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
return;
}
if (allNetworkNames.isEmpty()) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_CANNOT_FIND_NETWORK);
return;
}
LinkedHashMap<NetTrafficType, List<String>> networkConfig =
new LinkedHashMap<NetTrafficType, List<String>>();
if (networkName == null) {
if (allNetworkNames.size() == 1) {
networkConfig.put(NetTrafficType.MGT_NETWORK,
new ArrayList<String>());
networkConfig.get(NetTrafficType.MGT_NETWORK).addAll(
allNetworkNames);
} else {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_NETWORK_NAME + Constants.PARAM_NOT_SPECIFIED);
return;
}
} else {
if (!allNetworkNames.contains(networkName)
|| (hdfsNetworkName != null && !allNetworkNames
.contains(hdfsNetworkName))
|| (mapredNetworkName != null && !allNetworkNames
.contains(mapredNetworkName))) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_NETWORK_NAME + Constants.PARAM_NOT_SUPPORTED + allNetworkNames.toString());
return;
}
networkConfig.put(NetTrafficType.MGT_NETWORK, new ArrayList<String>());
networkConfig.get(NetTrafficType.MGT_NETWORK).add(networkName);
if (hdfsNetworkName != null) {
networkConfig.put(NetTrafficType.HDFS_NETWORK,
new ArrayList<String>());
networkConfig.get(NetTrafficType.HDFS_NETWORK).add(hdfsNetworkName);
}
if (mapredNetworkName != null) {
networkConfig.put(NetTrafficType.MAPRED_NETWORK,
new ArrayList<String>());
networkConfig.get(NetTrafficType.MAPRED_NETWORK).add(
mapredNetworkName);
}
}
notifyNetsUsage(networkConfig, warningMsgList);
clusterCreate.setNetworkConfig(networkConfig);
clusterCreate.validateCDHVersion(warningMsgList);
// Validate that the specified file is correct json format and proper value.
//TODO(qjin): 1, in validateClusterCreate, implement roles check and validation
// 2, consider use service to validate configuration for different appManager
if (specFilePath != null) {
validateClusterSpec(clusterCreate, failedMsgList, warningMsgList);
}
// give a warning message if both type and specFilePath are specified
if (type != null && specFilePath != null) {
warningMsgList.add(Constants.TYPE_SPECFILE_CONFLICT);
}
if (!failedMsgList.isEmpty()) {
showFailedMsg(clusterCreate.getName(), Constants.OUTPUT_OP_CREATE,
failedMsgList);
return;
}
// rest invocation
try {
if (!CommandsUtils.showWarningMsg(clusterCreate.getName(),
Constants.OUTPUT_OBJECT_CLUSTER, Constants.OUTPUT_OP_CREATE,
warningMsgList, alwaysAnswerYes, null)) {
return;
}
restClient.create(clusterCreate, BooleanUtils.toBoolean(skipVcRefresh));
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_CREAT);
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
CommandsUtils.getExceptionMessage(e));
return;
}
// check the instant clone type and the HA configuration for node groups
// currently there are limitations on HA support with instant clone, so we will
// display a warning message for instant clone with HA function
ClusterRead cluster = restClient.get(name, false);
if (cluster != null) {
String cloneType = cluster.getClusterCloneType();
String INSTANT_CLONE = com.vmware.bdd.utils.Constants.CLUSTER_CLONE_TYPE_INSTANT_CLONE;
if ( null != cloneType && cloneType.equals(INSTANT_CLONE) ) {
String warningMsg = validateInstantCloneWithHA(specFilePath, clusterCreate);
if ( !CommonUtil.isBlank(warningMsg) ) {
System.out.println(warningMsg);
}
}
}
}
private boolean hasLdapServiceUser(Map<String, Map<String, String>> serviceUserConfigs) {
for (Map<String, String> serviceUserConfig: serviceUserConfigs.values()) {
if (serviceUserConfig.get(UserMgmtConstants.SERVICE_USER_TYPE).equalsIgnoreCase("LDAP")) {
return true;
}
}
return false;
}
private void initInfraConfigs(Map<String, Map<String, String>> infraConfigs, Boolean disableLocalUsersFlag) {
Map<String, String> userMgmtConfigs = new HashMap<>();
//disable local account by default.
userMgmtConfigs.put(UserMgmtConstants.DISABLE_LOCAL_USER_FLAG,
disableLocalUsersFlag == null ? Boolean.TRUE.toString() : disableLocalUsersFlag.toString());
infraConfigs.put(UserMgmtConstants.LDAP_USER_MANAGEMENT, userMgmtConfigs);
}
protected void validateServiceUserConfigs(String appMangerName, ClusterCreate clusterSpec, List<String> failedMsgList) {
if (clusterSpec.getConfiguration() == null) {
return;
}
Map<String, Map<String, String>> serviceUserConfigs = (Map<String, Map<String, String>>)
clusterSpec.getConfiguration().get(UserMgmtConstants.SERVICE_USER_CONFIG_IN_SPEC_FILE);
if (MapUtils.isEmpty(serviceUserConfigs)) {
return;
}
String appManagerType = appManagerRestClient.get(appMangerName).getType();
String[] ambariSupportedConfigs = {
UserMgmtConstants.SERVICE_USER_NAME,
UserMgmtConstants.SERVICE_USER_TYPE};
String[] clouderaSupportedConfigs = {
UserMgmtConstants.SERVICE_USER_NAME,
UserMgmtConstants.SERVICE_USER_TYPE,
UserMgmtConstants.SERVICE_USER_GROUP
};
if (appManagerType.equals(Constants.IRONFAN)) {
failedMsgList.add("Ironfan deployed cluster doesn't support config service user");
} else if (appManagerType.equals(com.vmware.bdd.utils.Constants.AMBARI_PLUGIN_TYPE)) {
validateServiceUserConfigHelper(appManagerType, serviceUserConfigs, Arrays.asList(ambariSupportedConfigs), failedMsgList);
} else if (appManagerType.equals(com.vmware.bdd.utils.Constants.CLOUDERA_MANAGER_PLUGIN_TYPE)) {
validateServiceUserConfigHelper(appManagerType, serviceUserConfigs, Arrays.asList(clouderaSupportedConfigs), failedMsgList);
}
}
private void validateServiceUserConfigHelper(String appManagerType, Map<String, Map<String, String>> serviceUserConfigs,
List<String> supportedConfigs, List<String> failedMsgList) {
ArrayList<String> unSupportedKeys = new ArrayList<>();
for (Map<String, String> config : serviceUserConfigs.values()) {
for (String key: config.keySet()) {
if (!supportedConfigs.contains(key) && !unSupportedKeys.contains(key)) {
unSupportedKeys.add(key);
}
}
}
if (!unSupportedKeys.isEmpty()) {
failedMsgList.add(appManagerType + " deployed cluster doesn't support following keys when config service user: "
+ unSupportedKeys.toString());
}
}
private DistroRead getDistroByName(DistroRead[] distroReads,
String distroName) {
if (distroReads != null && distroName != null) {
for (DistroRead distroRead : distroReads) {
if (distroName.equals(distroRead.getName())) {
return distroRead;
}
}
}
return null;
}
private void validateClusterSpec(ClusterCreate clusterCreate,
List<String> failedMsgList, List<String> warningMsgList) {
clusterCreate.validateClusterCreate(failedMsgList, warningMsgList);
//validate roles and configuration.
com.vmware.bdd.apitypes.ValidateResult vr =
restClient.validateBlueprint(clusterCreate);
if (!vr.isValidated()) {
failedMsgList.addAll(vr.getFailedMsgList());
warningMsgList.addAll(vr.getWarningMsgList());
}
}
/**
* notify user which network Serengeti will pick up for mgt/hdfs/mapred
*
* @param networkConfig
* @param warningMsgList
*/
private void notifyNetsUsage(
Map<NetTrafficType, List<String>> networkConfig,
List<String> warningMsgList) {
if (!networkConfig.containsKey(NetTrafficType.HDFS_NETWORK)
&& !networkConfig.containsKey(NetTrafficType.MAPRED_NETWORK)) {
return;
}
String mgtNetwork = networkConfig.get(NetTrafficType.MGT_NETWORK).get(0);
String hdfsNetwork = mgtNetwork;
String mapredNetwork = mgtNetwork;
if (networkConfig.containsKey(NetTrafficType.HDFS_NETWORK)
&& !networkConfig.get(NetTrafficType.HDFS_NETWORK).isEmpty()) {
hdfsNetwork = networkConfig.get(NetTrafficType.HDFS_NETWORK).get(0);
}
if (networkConfig.containsKey(NetTrafficType.MAPRED_NETWORK)
&& !networkConfig.get(NetTrafficType.MAPRED_NETWORK).isEmpty()) {
mapredNetwork =
networkConfig.get(NetTrafficType.MAPRED_NETWORK).get(0);
}
StringBuffer netsUsage =
new StringBuffer().append("The cluster will use network ")
.append(mgtNetwork).append(" for management, ")
.append(hdfsNetwork).append(" for HDFS traffic, and ")
.append(mapredNetwork).append(" for MapReduce traffic.");
warningMsgList.add(netsUsage.toString());
}
private String getPassword() {
System.out.println("Hint: " + com.vmware.bdd.utils.Constants.PASSWORD_REQUIREMENT);
String firstPassword = getInputedPassword(Constants.ENTER_PASSWORD);
if (firstPassword == null) {
return null;
}
String secondPassword = getInputedPassword(Constants.CONFIRM_PASSWORD);
if (secondPassword == null) {
return null;
}
if (!firstPassword.equals(secondPassword)) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PASSWORD_CONFIRMATION_FAILED);
return null;
}
return firstPassword;
}
private String getInputedPassword(String promptMsg) {
try {
ConsoleReader reader = CommandsUtils.getConsoleReader();
reader.setPrompt(promptMsg);
String password = null;
password = reader.readLine(Character.valueOf('*'));
if (isValidPassword(password)) {
return password;
} else {
return null;
}
} catch (IOException e) {
return null;
}
}
private boolean isValidPassword(String password) {
if (!CommonUtil.validateClusterPassword(password)) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
com.vmware.bdd.utils.Constants.PASSWORD_REQUIREMENT);
return false;
}
return true;
}
@CliCommand(value = "cluster list", help = "Show cluster information")
public void getCluster(
@CliOption(key = { "name" }, mandatory = false, help = "The cluster name") final String name,
@CliOption(key = { "detail" }, mandatory = false, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = "flag to show node information") final boolean detail) {
// rest invocation
try {
if (name == null) {
ClusterRead[] clusters = restClient.getAll(detail);
if (clusters != null && clusters.length > 0) {
Arrays.sort(clusters);
prettyOutputClustersInfo(clusters, detail);
}
} else {
ClusterRead cluster = restClient.get(name, detail);
if (cluster != null) {
prettyOutputClusterInfo(cluster, detail);
printSeperator();
}
}
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_LIST, Constants.OUTPUT_OP_RESULT_FAIL,
e.getMessage());
}
}
@CliCommand(value = "cluster export", help = "Export cluster data")
public void exportClusterData(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String name,
@CliOption(key = { "specFile" }, mandatory = false, help = "The cluster spec file path") final String specFileName,
@CliOption(key = { "type" }, mandatory = false, help = "The data type to export: SPEC or RACK or IP2FQDN") final String type,
@CliOption(key = { "topology" }, mandatory = false, help = "The topology type: HVE or RACK_AS_RACK or HOST_AS_RACK") final String topology,
@CliOption(key = { "delimiter" }, mandatory = false, help = "The string used to separate each line") final String delimeter,
@CliOption(key = { "output" }, mandatory = false, help = "The path to the output file") final String output) {
// when neither fileName nor type is specified, path is null and when output, it will be replaced
// with System.out
String path = null;
if (!CommandsUtils.isBlank(specFileName)) {
if (!CommandsUtils.isBlank(type)) {
System.out.println(Constants.TYPE_SPECFILE_CONFLICT);
return;
}
path = specFileName;
} else if (!CommandsUtils.isBlank((type))) {
if (!CommandsUtils.isBlank(output)) {
path = output;
}
}
if (topology != null && validateTopologyValue(name, topology) == null) {
return;
}
try {
if ((CommandsUtils.isBlank(specFileName) && CommandsUtils
.isBlank(type))
|| !CommandsUtils.isBlank(specFileName)
|| Constants.EXPORT_TYPE_SPEC.equalsIgnoreCase(type)) {
ClusterCreate cluster = restClient.getSpec(name);
CommandsUtils.prettyJsonOutput(cluster, path);
} else if (Constants.EXPORT_TYPE_RACK.equalsIgnoreCase(type)) {
Map<String, String> rackTopology =
restClient.getRackTopology(name, topology);
CommandsUtils.gracefulRackTopologyOutput(rackTopology, path,
delimeter);
} else if (Constants.EXPORT_TYPE_IP.equalsIgnoreCase(type)) {
ClusterRead cluster = restClient.get(name, true);
prettyOutputClusterIPs(cluster, path, delimeter);
} else if (Constants.EXPORT_TYPE_IP_2_FQDN.equalsIgnoreCase(type)) {
ClusterRead cluster = restClient.get(name, true);
prettyOutputClusterIp2FqdnMapping(cluster, path, delimeter);
} else {
System.out.println(Constants.UNKNOWN_EXPORT_TYPE);
}
} catch (Exception e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_EXPORT, Constants.OUTPUT_OP_RESULT_FAIL,
e.getMessage());
}
}
@CliCommand(value = "cluster delete", help = "Delete a cluster")
public void deleteCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String name) {
// rest invocation
try {
restClient.delete(name);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_DELETE);
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_DELETE, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
@CliCommand(value = "cluster start", help = "Start a cluster")
public void startCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String clusterName,
@CliOption(key = { "force" }, mandatory = false, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = "Force start cluster") final Boolean forceStart) {
Map<String, String> queryStrings = new HashMap<String, String>();
queryStrings
.put(Constants.QUERY_ACTION_KEY, Constants.QUERY_ACTION_START);
queryStrings.put(Constants.FORCE_CLUSTER_OPERATION_KEY, forceStart.toString());
// rest invocation
try {
restClient.actionOps(clusterName, queryStrings);
CommandsUtils.printCmdSuccess(
Constants.OUTPUT_OBJECT_NODES_IN_CLUSTER,
Constants.OUTPUT_OP_RESULT_START);
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(
Constants.OUTPUT_OBJECT_NODES_IN_CLUSTER, Constants.OUTPUT_OP_START,
Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
@CliCommand(value = "cluster stop", help = "Stop a cluster")
public void stopCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String clusterName) {
Map<String, String> queryStrings = new HashMap<String, String>();
queryStrings.put(Constants.QUERY_ACTION_KEY, Constants.QUERY_ACTION_STOP);
// rest invocation
try {
restClient.actionOps(clusterName, queryStrings);
CommandsUtils.printCmdSuccess(
Constants.OUTPUT_OBJECT_NODES_IN_CLUSTER,
Constants.OUTPUT_OP_RESULT_STOP);
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_NODES_IN_CLUSTER,
Constants.OUTPUT_OP_STOP, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
@CliCommand(value = "cluster resize", help = "Resize a cluster")
public void resizeCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String name,
@CliOption(key = { "nodeGroup" }, mandatory = true, help = "The node group name") final String nodeGroup,
@CliOption(key = { "instanceNum" }, mandatory = false, unspecifiedDefaultValue = "0", help = "The new instance number, should be larger than 0") final int instanceNum,
@CliOption(key = { "cpuNumPerNode" }, mandatory = false, unspecifiedDefaultValue = "0", help = "The number of vCPU for the nodes in this group") final int cpuNumber,
@CliOption(key = { "memCapacityMbPerNode" }, mandatory = false, unspecifiedDefaultValue = "0", help = "The number of memory size in Mb for the nodes in this group") final long memory,
@CliOption(key = { "force" }, mandatory = false, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = "Ignore errors during resizing cluster") final Boolean force,
@CliOption(key = { "skipVcRefresh" }, mandatory = false, help = "flag to skip refreshing VC resources") final Boolean skipVcRefresh) {
if ((instanceNum > 0 && cpuNumber == 0 && memory == 0)
|| (instanceNum == 0 && (cpuNumber > 0 || memory > 0))) {
try {
ClusterRead cluster = restClient.get(name, false);
if (cluster == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESIZE, Constants.OUTPUT_OP_RESULT_FAIL,
"cluster " + name + " does not exist.");
return;
}
// disallow scale out zookeeper node group.
List<NodeGroupRead> ngs = cluster.getNodeGroups();
boolean found = false;
for (NodeGroupRead ng : ngs) {
if (ng.getName().equals(nodeGroup)) {
found = true;
/*if (ng.getRoles() != null
&& ng.getRoles().contains(
HadoopRole.ZOOKEEPER_ROLE.toString())
&& instanceNum > 1) {
CommandsUtils.printCmdFailure(
Constants.OUTPUT_OBJECT_CLUSTER, name,
Constants.OUTPUT_OP_RESIZE,
Constants.OUTPUT_OP_RESULT_FAIL,
Constants.ZOOKEEPER_NOT_RESIZE);
return;
}*/// TODO emma: do not check as client do not know who is Zookeeper
break;
}
}
if (!found) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESIZE, Constants.OUTPUT_OP_RESULT_FAIL,
"node group " + nodeGroup + " does not exist.");
return;
}
TaskRead taskRead = null;
if (instanceNum > 0) {
Map<String, String> queryStrings = new HashMap<String, String>();
queryStrings.put(Constants.FORCE_CLUSTER_OPERATION_KEY, force.toString());
queryStrings.put(Constants.REST_PARAM_SKIP_REFRESH_VC, Boolean.toString(BooleanUtils.toBoolean(skipVcRefresh)));
restClient.resize(name, nodeGroup, instanceNum, queryStrings);
} else if (cpuNumber > 0 || memory > 0) {
if (!cluster.getStatus().isActiveServiceStatus()) {
CommandsUtils.printCmdFailure(
Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESIZE,
Constants.OUTPUT_OP_RESULT_FAIL,
"Cluster must be in 'RUNNING' state to scale up/down");
return;
}
ResourceScale resScale =
new ResourceScale(name, nodeGroup, cpuNumber, memory);
taskRead = restClient.scale(resScale);
}
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_RESIZE);
if (taskRead != null) {
System.out.println();
printScaleReport(taskRead, name, nodeGroup);
}
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESIZE, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
} else {
if (instanceNum > 0 && (cpuNumber > 0 || memory > 0)) {
CommandsUtils
.printCmdFailure(
Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESIZE,
Constants.OUTPUT_OP_RESULT_FAIL,
"Can not scale out/in and scale up/down at the same time, you have to run those commands separately");
} else if (instanceNum == 0 && cpuNumber == 0 && memory == 0) {
CommandsUtils
.printCmdFailure(
Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESIZE,
Constants.OUTPUT_OP_RESULT_FAIL,
"You must specify one positive value for instanceNum/cpuNumPerNode/memCapacityMbPerNode");
} else {
List<String> invalidParams = new ArrayList<String>();
if (instanceNum < 0) {
invalidParams.add("instanceNum=" + instanceNum);
}
if (cpuNumber < 0) {
invalidParams.add("cpuNumPerNode=" + cpuNumber);
}
if (memory < 0) {
invalidParams.add("memCapacityMbPerNode=" + memory);
}
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESIZE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.INVALID_VALUE + " " + StringUtils.join(invalidParams, ", "));
}
}
}
@CliCommand(value = "cluster update", help = "Update resourcepools or datastores used by cluster")
public void updateCluster(
@CliOption(key = { "name" }, mandatory = true, help = "the cluster name") final String name,
@CliOption(key = { "rpNames" }, mandatory = false, help = "Resource Pools for the cluster: use \",\" among names.") final String rpNames,
@CliOption(key = { "dsNames" }, mandatory = false, help = "Datastores for the cluster: use \",\" among names.") final String dsNames,
@CliOption(key = { "append" }, mandatory = false, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = "Append the specified rpNames or dsNames to current value.") final Boolean append,
@CliOption(key = { "yes" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Answer 'yes' to all Y/N questions. ") final boolean alwaysAnswerYes) {
ClusterRead cluster = null;
try {
cluster = restClient.get(name, false);
if (cluster == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_UPDATE, Constants.OUTPUT_OP_RESULT_FAIL,
"cluster " + name + " does not exist.");
return;
}
}catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_UPDATE,
Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
return;
}
boolean ignoreWarning = alwaysAnswerYes;
boolean onlyAppend = append;
List<String> rpNamesList = new ArrayList<String>();
List<String> dsNamesList = new ArrayList<String>();
List<String> warningMsgList = new ArrayList<String>();
ClusterCreate clusterUpdate = new ClusterCreate();
clusterUpdate.setName(name);
//Check whether the new rpNames include all resourcepools which cluster already uses
if(!CommonUtil.isBlank(rpNames)){
rpNamesList.addAll(CommandsUtils.inputsConvertSet(rpNames));
clusterUpdate.setRpNames(rpNamesList);
}
//Check whether the new dsNames include all datastores which cluster already uses
if(!CommonUtil.isBlank(dsNames)){
dsNamesList.addAll(CommandsUtils.inputsConvertSet(dsNames));
clusterUpdate.setDsNames(dsNamesList);
}
if(!CommonUtil.isBlank(rpNames) || !CommonUtil.isBlank(dsNames)) {
try {
restClient.updateCluster(clusterUpdate, ignoreWarning, onlyAppend);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_UPDATE);
} catch (WarningMessageException e){
warningMsgList.add(CommonUtil.formatWarningMsg(e.getMessage()));
if(!CommandsUtils.showWarningMsg(cluster.getName(),
Constants.OUTPUT_OBJECT_CLUSTER, Constants.OUTPUT_OP_UPDATE,
warningMsgList, ignoreWarning, null)) {
return;
} else {
ignoreWarning = true;
restClient.updateCluster(clusterUpdate, ignoreWarning, onlyAppend);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_UPDATE);
}
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_UPDATE, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
} else {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_UPDATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_SHOULD_SPECIFY_RP_DS);
}
}
private void printScaleReport(TaskRead taskRead, String clusterName,
String nodeGroupName) {
ClusterRead cluster = restClient.get(clusterName, true);
List<NodeGroupRead> nodeGroups = cluster.getNodeGroups();
List<NodeStatus> succeedNodes = taskRead.getSucceedNodes();
List<NodeStatus> failedNodes = taskRead.getFailNodes();
setNodeStatusInfo(succeedNodes, nodeGroups);
setNodeStatusInfo(failedNodes, nodeGroups);
LinkedHashMap<String, List<String>> columnNamesWithGetMethodNames =
new LinkedHashMap<String, List<String>>();
columnNamesWithGetMethodNames.put("IP", Arrays.asList("getIp"));
columnNamesWithGetMethodNames.put("NAME", Arrays.asList("getNodeName"));
columnNamesWithGetMethodNames.put("CPU", Arrays.asList("getCpuNumber"));
columnNamesWithGetMethodNames.put("MEM(MB)", Arrays.asList("getMemory"));
columnNamesWithGetMethodNames.put("STATUS", Arrays.asList("getStatus"));
columnNamesWithGetMethodNames.put("NOTES",
Arrays.asList("getErrorMessage"));
try {
System.out.println("The resized node group: " + nodeGroupName);
System.out
.println("The current resized nodes: " + succeedNodes.size());
CommandsUtils.printInTableFormat(columnNamesWithGetMethodNames,
succeedNodes.toArray(), Constants.OUTPUT_INDENT);
System.out.println("The failed resized nodes: " + failedNodes.size());
CommandsUtils.printInTableFormat(columnNamesWithGetMethodNames,
failedNodes.toArray(), Constants.OUTPUT_INDENT);
} catch (Exception e) {
throw new CliRestException(e.getMessage());
}
}
private void setNodeStatusInfo(List<NodeStatus> nodes,
List<NodeGroupRead> nodeGroups) {
for (NodeStatus nodeStatus : nodes) {
NodeRead node = getNodeRead(nodeStatus.getNodeName(), nodeGroups);
if (node != null) {
// only show the management Ip currently
nodeStatus.setIp(node.fetchMgtIp());
nodeStatus.setStatus(node.getStatus());
nodeStatus.setCpuNumber(node.getCpuNumber());
nodeStatus.setMemory(node.getMemory());
}
}
}
@CliCommand(value = "cluster setParam", help = "set cluster parameters")
public void setParam(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String clusterName,
@CliOption(key = { "ioShares" }, mandatory = false, help = "The relative disk I/O priorities: HIGH, NORNAL, LOW") final String ioShares) {
try {
//validate if the cluster exists
ClusterRead cluster = restClient.get(clusterName, false);
if (cluster == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_SET_PARAM, Constants.OUTPUT_OP_RESULT_FAIL,
"cluster " + clusterName + " does not exist.");
return;
}
if (ioShares == null) {
// in this case, no parameter is specified excpet "cluster name", return directly
System.out
.println("There is nothing to adjust, please specify more parameters.");
return;
}
//validate the input of ioShares
Priority ioPriority = null;
if (ioShares != null) {
try {
ioPriority = Priority.valueOf(ioShares.toUpperCase());
} catch (IllegalArgumentException ex) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_SET_PARAM, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.INVALID_VALUE + " " + "ioShares = " + ioShares);
return;
}
}
ElasticityRequestBody requestBody = new ElasticityRequestBody();
requestBody.setIoPriority(ioPriority);
restClient.setParam(cluster, requestBody);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_ADJUST);
} catch (CliRestException e) {
if (e.getMessage() != null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_SET_PARAM, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
}
@CliCommand(value = "cluster resetParam", help = "reset cluster parameters")
public void resetParam(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String clusterName,
@CliOption(key = { "ioShares" }, mandatory = true, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", help = "reset disk I/O priorities to LOW") final boolean ioShares) {
try {
//validate if the cluster exists
ClusterRead cluster = restClient.get(clusterName, false);
if (cluster == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESET_PARAM, Constants.OUTPUT_OP_RESULT_FAIL,
"cluster " + clusterName + " does not exist.");
return;
}
// ioShares: normal
ElasticityRequestBody requestBody = new ElasticityRequestBody();
if (ioShares) {
requestBody.setIoPriority(Priority.NORMAL);
}
restClient.setParam(cluster, requestBody);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_RESET);
} catch (CliRestException e) {
if (e.getMessage() != null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER, Constants.OUTPUT_OP_RESET_PARAM,
Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
}
@CliCommand(value = "cluster config", help = "Config an existing cluster")
public void configCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String name,
@CliOption(key = { "specFile" }, mandatory = true, help = "The spec file name path") final String specFilePath,
@CliOption(key = { "skipConfigValidation" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Skip cluster configuration validation. ") final boolean skipConfigValidation,
@CliOption(key = { "yes" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Answer 'yes' to all Y/N questions. ") final boolean alwaysAnswerYes) {
// validate the name
if (name.indexOf("-") != -1) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CONFIG, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_CLUSTER + Constants.PARAM_NOT_CONTAIN_HORIZONTAL_LINE);
return;
}
try {
ClusterRead clusterRead = restClient.get(name, false);
// build ClusterCreate object
ClusterCreate clusterConfig = new ClusterCreate();
clusterConfig.setName(clusterRead.getName());
ClusterCreate clusterSpec =
CommandsUtils.getObjectByJsonString(ClusterCreate.class,
CommandsUtils.dataFromFile(specFilePath));
clusterConfig.setNodeGroups(clusterSpec.getNodeGroups());
clusterConfig.setConfiguration(clusterSpec.getConfiguration());
clusterConfig.setExternalHDFS(clusterSpec.getExternalHDFS());
List<String> warningMsgList = new ArrayList<String>();
List<String> failedMsgList = new ArrayList<String>();
validateConfiguration(clusterConfig, skipConfigValidation,
warningMsgList, failedMsgList);
// add a confirm message for running job
warningMsgList.add("Warning: "
+ Constants.PARAM_CLUSTER_CONFIG_RUNNING_JOB_WARNING);
if (!CommandsUtils.showWarningMsg(clusterConfig.getName(),
Constants.OUTPUT_OBJECT_CLUSTER, Constants.OUTPUT_OP_CONFIG,
warningMsgList, alwaysAnswerYes, null)) {
return;
}
if (!failedMsgList.isEmpty()) {
showFailedMsg(clusterConfig.getName(), Constants.OUTPUT_OP_CONFIG,
failedMsgList);
return;
}
restClient.configCluster(clusterConfig);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_CONFIG);
} catch (Exception e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CONFIG, Constants.OUTPUT_OP_RESULT_FAIL,
e.getMessage());
return;
}
}
@CliCommand(value = "cluster fix", help = "Fix a cluster failure")
public void fixCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String clusterName,
@CliOption(key = { "disk" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Recover a disk failure") final boolean isDiskFailure,
@CliOption(key = { "parallel" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Whether use parallel way to recovery node or not") final boolean parallel,
@CliOption(key = { "nodeGroup" }, mandatory = false, help = "The node group name which failure belong to") final String nodeGroupName) {
try {
TaskRead taskRead = null;
if (!isDiskFailure) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER, Constants.OUTPUT_OP_FIX,
Constants.OUTPUT_OP_RESULT_FAIL, Constants.PARAM_SHOULD_SPECIFY_DISK);
return;
} else {
FixDiskRequestBody requestBody = new FixDiskRequestBody();
requestBody.setParallel(parallel);
if (!CommandsUtils.isBlank(nodeGroupName)) {
requestBody.setNodeGroupName(nodeGroupName);
}
taskRead = restClient.fixDisk(clusterName, requestBody);
if (taskRead == null) {
return;
}
}
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_FIX);
System.out.println();
printClusterFixReport(taskRead, clusterName);
} catch (Exception e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_FIX, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
return;
}
}
@CliCommand(value = "cluster upgrade", help = "Upgrade an old cluster")
public void upgradeCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String name,
@CliOption(key = { "yes" }, mandatory = false, unspecifiedDefaultValue = "false", specifiedDefaultValue = "true", help = "Answer 'yes' to all Y/N questions. ") final boolean alwaysAnswerYes)
throws IOException {
// validate the name
if (name.indexOf("-") != -1) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_UPGRADE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_CLUSTER + Constants.PARAM_NOT_CONTAIN_HORIZONTAL_LINE);
return;
}
// rest invocation
try {
// add a confirm message
List<String> warningMsgList = new ArrayList<String>();
warningMsgList.add("Warning: " + Constants.PARAM_PROMPT_UPGRADE_CLUSTER_WARNING);
if (!CommandsUtils.showWarningMsg(name,
Constants.OUTPUT_OBJECT_CLUSTER, Constants.OUTPUT_OP_UPGRADE,
warningMsgList, alwaysAnswerYes, null)) {
return;
}
restClient.upgradeCluster(name);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_UPGRADE);
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_UPGRADE, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
private void printClusterFixReport(TaskRead taskRead, String clusterName)
throws Exception {
ClusterRead cluster = restClient.get(clusterName, true);
List<NodeGroupRead> nodeGroups = cluster.getNodeGroups();
List<NodeStatus> succeedNodes = taskRead.getSucceedNodes();
List<NodeStatus> failedNodes = taskRead.getFailNodes();
setNodeStatusInfo(succeedNodes, nodeGroups);
System.out.println("The fixed nodes: " + succeedNodes.size());
LinkedHashMap<String, List<String>> columnNamesWithGetMethodNames =
new LinkedHashMap<String, List<String>>();
columnNamesWithGetMethodNames.put("IP", Arrays.asList("getIp"));
columnNamesWithGetMethodNames.put("NAME", Arrays.asList("getNodeName"));
columnNamesWithGetMethodNames.put("STATUS", Arrays.asList("getStatus"));
CommandsUtils.printInTableFormat(columnNamesWithGetMethodNames,
succeedNodes.toArray(), Constants.OUTPUT_INDENT);
if (failedNodes.size() > 0) {
System.out.println("The failed nodes: " + failedNodes.size());
}
setNodeStatusInfo(failedNodes, nodeGroups);
columnNamesWithGetMethodNames.put("Error Message",
Arrays.asList("getErrorMessage"));
CommandsUtils.printInTableFormat(columnNamesWithGetMethodNames,
failedNodes.toArray(), Constants.OUTPUT_INDENT);
}
private NodeRead getNodeRead(String nodeName, List<NodeGroupRead> nodeGroups) {
for (NodeGroupRead nodeGroup : nodeGroups) {
List<NodeRead> nodes = nodeGroup.getInstances();
for (NodeRead node : nodes) {
if (node.getName().equals(nodeName)) {
return node;
}
}
}
return null;
}
private void resumeCreateCluster(final String name, Boolean skipVcRefresh) {
Map<String, String> queryStrings = new HashMap<String, String>();
queryStrings.put(Constants.QUERY_ACTION_KEY,
Constants.QUERY_ACTION_RESUME);
queryStrings.put(Constants.REST_PARAM_SKIP_REFRESH_VC, Boolean.toString(BooleanUtils.toBoolean(skipVcRefresh)));
try {
restClient.actionOps(name, queryStrings);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_RESUME);
} catch (CliRestException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESUME, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
private Set<String> getAllNetworkNames() {
Set<String> allNetworks = new HashSet<String>();
NetworkRead[] networks = networkRestClient.getAll(false);
if (networks != null) {
for (NetworkRead network : networks) {
allNetworks.add(network.getName());
}
}
return allNetworks;
}
private List<String> getDistroNames(DistroRead[] distroReads) {
List<String> distroNames = new ArrayList<String>();
if (distroReads != null) {
for (int i = 0; i < distroReads.length; i++) {
distroNames.add(distroReads[i].getName());
}
}
return distroNames;
}
private boolean validName(String inputName, List<String> validNames) {
for (String name : validNames) {
if (name.equals(inputName)) {
return true;
}
}
return false;
}
private void prettyOutputClusterInfo(ClusterRead cluster, boolean detail) {
Map<String, Map<String, String>> infraCfg = cluster.getInfrastructure_config();
Map<String, String> userMgmtCfg = null;
if (MapUtils.isNotEmpty(infraCfg)) {
userMgmtCfg = infraCfg.get(UserMgmtConstants.LDAP_USER_MANAGEMENT);
}
TopologyType topology = cluster.getTopologyPolicy();
printSeperator();
// list cluster level params
LinkedHashMap<String, String> clusterParams =
new LinkedHashMap<String, String>();
clusterParams.put("CLUSTER NAME", cluster.getName());
clusterParams.put("AGENT VERSION", cluster.getVersion());
clusterParams.put("APP MANAGER", cluster.getAppManager());
clusterParams.put("DISTRO", cluster.getDistro());
clusterParams.put("NODE TEMPLATE", cluster.getTemplateName());
String cloneType = cluster.getClusterCloneType();
if (!CommandsUtils.isBlank(cloneType)) {
clusterParams.put("CLUSTER CLONE TYPE", cloneType.toUpperCase());
}
if (topology != null && topology != TopologyType.NONE) {
clusterParams.put("TOPOLOGY", topology.toString());
}
clusterParams.put("IO SHARES", cluster.getIoShares() == null ? ""
: cluster.getIoShares().toString());
clusterParams.put("STATUS", cluster.getStatus() == null ? "" : cluster
.getStatus().toString());
if (cluster.getExternalHDFS() != null
&& !cluster.getExternalHDFS().isEmpty()) {
clusterParams.put("EXTERNAL HDFS", cluster.getExternalHDFS());
}
//Burst out
if (!CommandsUtils.isBlank(cluster.getExternalMapReduce())) {
clusterParams
.put("EXTERNAL MAPREDUCE", cluster.getExternalMapReduce());
}
clusterParams.put("AD/LDAP ENABLED", Boolean.toString(MapUtils.isNotEmpty(userMgmtCfg)));
for (String key : clusterParams.keySet()) {
System.out.printf(Constants.OUTPUT_INDENT + "%-26s:"
+ Constants.OUTPUT_INDENT + "%s\n", key, clusterParams.get(key));
}
System.out.println();
LinkedHashMap<String, List<String>> ngColumnNamesWithGetMethodNames =
new LinkedHashMap<String, List<String>>();
List<NodeGroupRead> nodegroups = cluster.getNodeGroups();
if (nodegroups != null) {
ngColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_GROUP_NAME,
Arrays.asList("getName"));
ngColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_ROLES, Arrays.asList("getRoles"));
ngColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_INSTANCE,
Arrays.asList("getInstanceNum"));
ngColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_CPU,
Arrays.asList("getCpuNum"));
ngColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_MEM,
Arrays.asList("getMemCapacityMB"));
ngColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_TYPE,
Arrays.asList("getStorage", "getType"));
ngColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_SIZE,
Arrays.asList("getStorage", "getSizeGB"));
try {
if (detail) {
prettyOutputDetailNodegroups(topology,
ngColumnNamesWithGetMethodNames, nodegroups);
} else
CommandsUtils.printInTableFormat(
ngColumnNamesWithGetMethodNames, nodegroups.toArray(),
Constants.OUTPUT_INDENT);
} catch (Exception e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_LIST, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
if(detail) {
prettyOutputDetailedUserMgmt(cluster.getName(), userMgmtCfg);
}
}
}
protected static void prettyOutputDetailedUserMgmt(String clusterName, Map<String, String> userMgmtCfg) {
try {
if (MapUtils.isNotEmpty(userMgmtCfg)) {
if (MapUtils.isEmpty(USER_MGMT_COLUMN_FORMAT)) {
USER_MGMT_COLUMN_FORMAT = new LinkedHashMap<>();
USER_MGMT_COLUMN_FORMAT.put("ADMINISTRATORS GROUP", Arrays.asList(UserMgmtConstants.ADMIN_GROUP_NAME));
USER_MGMT_COLUMN_FORMAT.put("USERS GROUP", Arrays.asList(UserMgmtConstants.USER_GROUP_NAME));
USER_MGMT_COLUMN_FORMAT.put("LOCAL USERS DISABLED", Arrays.asList(UserMgmtConstants.DISABLE_LOCAL_USER_FLAG));
}
CommandsUtils.printInTableFormat(USER_MGMT_COLUMN_FORMAT, Arrays.asList(((Map) userMgmtCfg)), Constants.OUTPUT_INDENT);
}
} catch (Exception e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_LIST, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
}
}
private void prettyOutputDetailNodegroups(TopologyType topology,
LinkedHashMap<String, List<String>> ngColumnNamesWithGetMethodNames,
List<NodeGroupRead> nodegroups) throws Exception {
LinkedHashMap<String, List<String>> nColumnNamesWithGetMethodNames =
new LinkedHashMap<String, List<String>>();
nColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_NODE_NAME, Arrays.asList("getName"));
nColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_NODE_VERSION,
Arrays.asList("getVersion"));
nColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_HOST,
Arrays.asList("getHostName"));
if (topology == TopologyType.RACK_AS_RACK || topology == TopologyType.HVE) {
nColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_RACK,
Arrays.asList("getRack"));
}
nColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_IP,
Arrays.asList("fetchMgtIp"));
nColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_HDFS_IP,
Arrays.asList("fetchHdfsIp"));
nColumnNamesWithGetMethodNames.put(
Constants.FORMAT_TABLE_COLUMN_MAPRED_IP,
Arrays.asList("fetchMapredIp"));
nColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_STATUS,
Arrays.asList("getStatus"));
nColumnNamesWithGetMethodNames.put(Constants.FORMAT_TABLE_COLUMN_TASK,
Arrays.asList("getAction"));
for (NodeGroupRead nodegroup : nodegroups) {
CommandsUtils.printInTableFormat(ngColumnNamesWithGetMethodNames,
new NodeGroupRead[] { nodegroup }, Constants.OUTPUT_INDENT);
List<NodeRead> nodes = nodegroup.getInstances();
if (nodes != null) {
LinkedHashMap<String, List<String>> nColumnNamesWithGetMethodNamesClone =
(LinkedHashMap<String, List<String>>) nColumnNamesWithGetMethodNames
.clone();
if (!nodes.isEmpty()
&& (nodes.get(0).getIpConfigs() == null || (!nodes.get(0)
.getIpConfigs()
.containsKey(NetTrafficType.HDFS_NETWORK) && !nodes
.get(0).getIpConfigs()
.containsKey(NetTrafficType.MAPRED_NETWORK)))) {
nColumnNamesWithGetMethodNamesClone
.remove(Constants.FORMAT_TABLE_COLUMN_HDFS_IP);
nColumnNamesWithGetMethodNamesClone
.remove(Constants.FORMAT_TABLE_COLUMN_MAPRED_IP);
}
System.out.println();
CommandsUtils.printInTableFormat(
nColumnNamesWithGetMethodNamesClone,
nodes.toArray(),
new StringBuilder().append(Constants.OUTPUT_INDENT)
.append(Constants.OUTPUT_INDENT).toString());
}
System.out.println();
}
CommandsUtils.prettyOutputErrorNode(nodegroups);
}
private void prettyOutputClustersInfo(ClusterRead[] clusters, boolean detail) {
for (ClusterRead cluster : clusters) {
prettyOutputClusterInfo(cluster, detail);
}
printSeperator();
}
private void printSeperator() {
StringBuffer seperator =
new StringBuffer().append(Constants.OUTPUT_INDENT);
for (int i = 0; i < Constants.SEPERATOR_LEN; i++) {
seperator.append("=");
}
System.out.println(seperator.toString());
System.out.println();
}
public static void prettyOutputClusterIPs(ClusterRead cluster,
String filename, String delimeter) throws Exception {
List<Object> list = new ArrayList<Object>();
for (NodeGroupRead nodegroup : cluster.getNodeGroups()) {
List<NodeRead> nodes = nodegroup.getInstances();
if (nodes != null && !nodes.isEmpty()) {
for (NodeRead node : nodes) {
list.add(node.fetchMgtIp());
}
}
}
CommandsUtils.prettyOutputStrings(list, filename, delimeter);
}
private void showFailedMsg(String name, String op, List<String> failedMsgList) {
// cluster creation failed message.
StringBuilder failedMsg = new StringBuilder();
failedMsg.append(Constants.INVALID_VALUE);
if (failedMsgList.size() > 1) {
failedMsg.append("s");
}
failedMsg.append(".\n");
failedMsg.append(new ListToStringConverter<String>(failedMsgList, '\n'));
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER, op,
Constants.OUTPUT_OP_RESULT_FAIL, failedMsg.toString());
}
private void validateConfiguration(ClusterCreate cluster,
boolean skipConfigValidation, List<String> warningMsgList,
List<String> failedMsgList) {
// validate blacklist
ValidateResult blackListResult = validateBlackList(cluster);
addBlackListWarning(blackListResult, warningMsgList);
if (!skipConfigValidation) {
// validate config type
AppConfigValidationUtils.validateSupportType(
cluster.getConfiguration(), warningMsgList);
// validate whitelist
ValidateResult whiteListResult = validateWhiteList(cluster);
addWhiteListWarningOrFailure(cluster.getName(), whiteListResult,
warningMsgList, failedMsgList);
} else {
cluster.setValidateConfig(false);
}
}
private ValidateResult validateBlackList(ClusterCreate cluster) {
return validateConfiguration(cluster, ValidationType.BLACK_LIST);
}
private ValidateResult validateWhiteList(ClusterCreate cluster) {
return validateConfiguration(cluster, ValidationType.WHITE_LIST);
}
/*
* Validate a configuration of the cluster at first. Validate configurations
* of all of node groups then. And merge the failed info which have been
* producted by validation between cluster level and node group level.
*/
private ValidateResult validateConfiguration(ClusterCreate cluster,
ValidationType validationType) {
ValidateResult validateResult = new ValidateResult();
// validate cluster level Configuration
ValidateResult vr = null;
if (cluster.getConfiguration() != null
&& !cluster.getConfiguration().isEmpty()) {
vr =
AppConfigValidationUtils.validateConfig(validationType,
cluster.getConfiguration());
if (vr.getType() != ValidateResult.Type.VALID) {
validateResult.setType(vr.getType());
if (!vr.getFailureNames().isEmpty()) {
validateResult.setFailureNames(vr.getFailureNames());
}
if (!vr.getFailureValues().isEmpty()) {
validateResult.setFailureValues(vr.getFailureValues());
}
if (!vr.getNoExistFileNames().isEmpty()) {
validateResult.setNoExistFileNames(vr.getNoExistFileNames());
}
}
}
List<String> failureNames = new ArrayList<String>();
Map<String, List<String>> noExistingFileNamesMap =
new HashMap<String, List<String>>();
List<String> failureValues = new ArrayList<String>();
if (!validateResult.getFailureNames().isEmpty()) {
failureNames.addAll(validateResult.getFailureNames());
}
if (!validateResult.getNoExistFileNames().isEmpty()) {
noExistingFileNamesMap.putAll(validateResult.getNoExistFileNames());
}
if (!validateResult.getFailureValues().isEmpty()) {
failureValues.addAll(validateResult.getFailureValues());
}
// validate nodegroup level Configuration
for (NodeGroupCreate nodeGroup : cluster.getNodeGroups()) {
if (nodeGroup.getConfiguration() != null
&& !nodeGroup.getConfiguration().isEmpty()) {
vr =
AppConfigValidationUtils.validateConfig(validationType,
nodeGroup.getConfiguration());
if (vr.getType() != ValidateResult.Type.VALID) {
//invalid value will take higher priority than invalid name as it will throw failure
if (validateResult.getType() != ValidateResult.Type.WHITE_LIST_INVALID_VALUE) {
validateResult.setType(vr.getType());
}
// merge failed names between cluster level and node group level.
for (String failureName : vr.getFailureNames()) {
if (!failureNames.contains(failureName)) {
failureNames.add(failureName);
}
}
// merge failed names between cluster level and node group level.
for (String failureValue : vr.getFailureValues()) {
if (!failureValues.contains(failureValue)) {
failureValues.add(failureValue);
}
}
// merge no existing file names between cluster level and node
// group level
for (Entry<String, List<String>> noExistingFileNames : vr
.getNoExistFileNames().entrySet()) {
String configType = noExistingFileNames.getKey();
if (noExistingFileNamesMap.containsKey(configType)) {
List<String> noExistingFilesTemp =
noExistingFileNames.getValue();
List<String> noExistingFiles =
noExistingFileNamesMap.get(configType);
for (String fileName : noExistingFilesTemp) {
if (!noExistingFiles.contains(fileName)) {
noExistingFiles.add(fileName);
}
}
noExistingFileNamesMap.put(configType, noExistingFiles);
} else {
noExistingFileNamesMap.put(configType,
noExistingFileNames.getValue());
}
}
}
}
}
validateResult.setFailureNames(failureNames);
validateResult.setNoExistFileNames(noExistingFileNamesMap);
validateResult.setFailureValues(failureValues);
return validateResult;
}
private void addWhiteListWarningOrFailure(final String clusterName,
ValidateResult whiteListResult, List<String> warningMsgList,
List<String> failedMsgList) {
if (whiteListResult.getType() == ValidateResult.Type.WHITE_LIST_INVALID_NAME) {
String noExistingWarningMsg =
getValidateWarningMsg(whiteListResult.getNoExistFileNames());
String failureNameWarningMsg =
getValidateWarningMsg(whiteListResult.getFailureNames(),
Constants.PARAM_CLUSTER_NOT_IN_WHITE_LIST_WARNING);
if (warningMsgList != null) {
if (!CommonUtil.isBlank(noExistingWarningMsg)) {
warningMsgList.add(noExistingWarningMsg);
}
if (!CommonUtil.isBlank(failureNameWarningMsg)) {
warningMsgList.add(failureNameWarningMsg);
}
}
} else if (whiteListResult.getType() == ValidateResult.Type.WHITE_LIST_INVALID_VALUE) {
if (!whiteListResult.getFailureValues().isEmpty()) {
failedMsgList.addAll(whiteListResult.getFailureValues());
}
}
}
private void addBlackListWarning(ValidateResult blackListResult,
List<String> warningList) {
if (blackListResult.getType() == ValidateResult.Type.NAME_IN_BLACK_LIST) {
String warningMsg =
getValidateWarningMsg(blackListResult.getFailureNames(),
Constants.PARAM_CLUSTER_IN_BLACK_LIST_WARNING
+ Constants.PARAM_CLUSTER_NOT_TAKE_EFFECT);
if (warningList != null) {
if (!CommandsUtils.isBlank(warningMsg)) {
warningList.add(warningMsg);
}
}
}
}
private String getValidateWarningMsg(List<String> failureNames,
String warningMsg) {
StringBuilder warningMsgBuff = new StringBuilder();
if (failureNames != null && !failureNames.isEmpty()) {
warningMsgBuff.append("Warning: ");
for (String failureName : failureNames) {
warningMsgBuff.append(failureName).append(", ");
}
warningMsgBuff.delete(warningMsgBuff.length() - 2,
warningMsgBuff.length());
if (failureNames.size() > 1) {
warningMsgBuff.append(" are ");
} else {
warningMsgBuff.append(" is ");
}
warningMsgBuff.append(warningMsg);
}
return warningMsgBuff.toString();
}
private String getValidateWarningMsg(
Map<String, List<String>> noExistingFilesMap) {
StringBuilder warningMsgBuff = new StringBuilder();
if (noExistingFilesMap != null && !noExistingFilesMap.isEmpty()) {
warningMsgBuff.append("Warning: ");
for (Entry<String, List<String>> noExistingFilesEntry : noExistingFilesMap
.entrySet()) {
List<String> noExistingFileNames = noExistingFilesEntry.getValue();
for (String noExistingFileName : noExistingFileNames) {
warningMsgBuff.append(noExistingFileName).append(", ");
}
warningMsgBuff.delete(warningMsgBuff.length() - 2,
warningMsgBuff.length());
if (noExistingFileNames.size() > 1) {
warningMsgBuff.append(" are ");
} else {
warningMsgBuff.append(" is ");
}
warningMsgBuff.append("not existing in ");
warningMsgBuff.append(noExistingFilesEntry.getKey() + " scope , ");
}
warningMsgBuff.replace(warningMsgBuff.length() - 2,
warningMsgBuff.length(), ". ");
warningMsgBuff.append(Constants.PARAM_CLUSTER_NOT_TAKE_EFFECT);
}
return warningMsgBuff.toString();
}
private boolean validateHAInfo(NodeGroupCreate[] nodeGroups) {
List<String> haFlagList = Arrays.asList("off", "on", "ft");
if (nodeGroups != null) {
for (NodeGroupCreate group : nodeGroups) {
if (!haFlagList.contains(group.getHaFlag().toLowerCase())) {
return false;
}
}
}
return true;
}
private TopologyType validateTopologyValue(String clusterName,
String topology) {
TopologyType value = null;
try {
value = TopologyType.valueOf(topology);
} catch (IllegalArgumentException ex) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_CREATE, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.INVALID_VALUE + " " + "topologyType=" + topology);
}
return value;
}
public static void prettyOutputClusterIp2FqdnMapping(ClusterRead cluster,
String filename, String delimeter) throws Exception {
List<Object> list = new ArrayList<Object>();
for (NodeGroupRead nodegroup : cluster.getNodeGroups()) {
List<NodeRead> nodes = nodegroup.getInstances();
if (nodes != null && !nodes.isEmpty()) {
for (NodeRead node : nodes) {
if (node.getIpConfigs() != null) {
for (NetTrafficType trafficType : node.getIpConfigs().keySet()) {
String ip2Fqdn = String.format("%-15s", node.fetchIpOf(trafficType)) + " " + node.fetchFqdnOf(trafficType);
if (!list.contains(ip2Fqdn)) {
list.add(ip2Fqdn);
}
}
}
}
}
}
CommandsUtils.prettyOutputStrings(list, filename, delimeter);
}
private String validateInstantCloneWithHA(String specFilePath, ClusterCreate cluster) {
String warningMsg = null;
ArrayList<String> ngs = new ArrayList<String>();
if ( null != specFilePath ) {
NodeGroupCreate[] nodeGroups = cluster.getNodeGroups();
if ( null != nodeGroups ) {
for ( NodeGroupCreate ngc : nodeGroups ) {
String haFlag = ngc.getHaFlag();
if ( null != haFlag && !haFlag.equals(com.vmware.bdd.utils.Constants.HA_FLAG_OFF) ) {
ngs.add(ngc.getName());
}
}
}
} else {
// currently if user does not provide spec file, the default HA option for master group is
// set to 'on'
ngs.add("master");
}
if ( ngs.size() > 0 ) {
warningMsg = String.format(Constants.WARNING_INSTANT_CLONE_WITH_HA, ngs.toString());
}
return warningMsg;
}
@CliCommand(value = "cluster expand", help = "Expand element for existed cluster")
public void expandCluster(
@CliOption(key = { "name" }, mandatory = true, help = "The cluster name") final String name,
@CliOption(key = { "specFile" }, mandatory = true, help = "The spec file name path") final String specFilePath
) {
try {
if (specFilePath == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_EXPAND, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_NOT_CONTAIN_SPECFILE);
return;
}
ClusterRead cluster = restClient.get(name, false);
if (cluster == null) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_EXPAND, Constants.OUTPUT_OP_RESULT_FAIL,
"cluster " + name + " does not exist.");
return;
}
NodeGroupAdd nodeGroupAdd = new NodeGroupAdd();
NodeGroupAdd nodeGroupAddSpec = CommandsUtils.getObjectByJsonString(NodeGroupAdd.class,
CommandsUtils.dataFromFile(specFilePath));
nodeGroupAdd.setSpecFile(true);
nodeGroupAdd.setNodeGroups(nodeGroupAddSpec.getNodeGroups());
// validate the name
if (name.indexOf("-") != -1) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_EXPAND, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_NODEGROUP + Constants.PARAM_NOT_CONTAIN_HORIZONTAL_LINE);
return;
} else if (name.indexOf(" ") != -1) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_EXPAND, Constants.OUTPUT_OP_RESULT_FAIL,
Constants.PARAM_NODEGROUP + Constants.PARAM_NOT_CONTAIN_BLANK_SPACE);
return;
}
restClient.addNodeGroups(name, nodeGroupAdd);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_EXPAND);
} catch (Exception e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_EXPAND, Constants.OUTPUT_OP_RESULT_FAIL, e.getMessage());
return;
}
}
@CliCommand(value = "cluster recover", help = "Recover clusters")
public void recoverCluster(
@CliOption(key = { "resMapFile" }, mandatory = false, help = "The resource map file name path") final String mapFilePath) {
try {
VcResourceMap vcResMap = new VcResourceMap();
if ( null != mapFilePath ) {
vcResMap = CommandsUtils.getObjectByJsonString(VcResourceMap.class,
CommandsUtils.dataFromFile(mapFilePath));
}
restClient.recover(vcResMap);
CommandsUtils.printCmdSuccess(Constants.OUTPUT_OBJECT_CLUSTER_ALL,
Constants.OUTPUT_OP_RESULT_RECOVER_SUCC);
} catch (CliRestException | IOException e) {
CommandsUtils.printCmdFailure(Constants.OUTPUT_OBJECT_CLUSTER,
Constants.OUTPUT_OP_RESULT_RECOVER, Constants.OUTPUT_OP_RESULT_FAIL,
e.getMessage());
}
}
}