/***************************************************************************
* 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.plugin.ironfan.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import com.vmware.bdd.apitypes.Datastore.DatastoreType;
import com.vmware.bdd.apitypes.PlacementPolicy;
import com.vmware.bdd.apitypes.PlacementPolicy.GroupAssociation;
import com.vmware.bdd.exception.BddException;
import com.vmware.bdd.exception.ClusterConfigException;
import com.vmware.bdd.software.mgmt.plugin.model.ClusterBlueprint;
import com.vmware.bdd.software.mgmt.plugin.model.NodeGroupInfo;
import com.vmware.bdd.spectypes.GroupType;
import com.vmware.bdd.spectypes.HadoopRole;
import com.vmware.bdd.spectypes.HadoopRole.RoleComparactor;
import com.vmware.bdd.spectypes.ServiceType;
public class InfrastructureUpdator {
private static final Logger logger = Logger.getLogger(InfrastructureUpdator.class);
private ClusterValidator validator;
public void setValidator(ClusterValidator validator) {
this.validator = validator;
}
public void updateInfrastructure(ClusterBlueprint blueprint) {
updateExternalConfig(blueprint);
addTempFSServerRole(blueprint);
sortNodeGroupRoles(blueprint);
}
private void updateExternalConfig(ClusterBlueprint blueprint) {
if (blueprint.getExternalHDFS() == null) {
setExternalHDFSFromConf(blueprint);
} else {
setHadoopConfFromExternalHDFS(blueprint);
}
if (blueprint.getExternalMapReduce() == null) {
setExternalMapReduceFromConf(blueprint);
} else {
setHadoopConfFromExternalMapReduce(blueprint);
}
}
private void sortNodeGroupRoles(ClusterBlueprint blueprint) {
for (NodeGroupInfo nodeGroup : blueprint.getNodeGroups()) {
List<String> roles = nodeGroup.getRoles();
List<String> unSupportedRoles = new ArrayList<String>();
EnumSet<HadoopRole> enumRoles = HadoopRole.getEnumRoles(roles, unSupportedRoles);
if (enumRoles.isEmpty()) {
throw ClusterConfigException.NO_HADOOP_ROLE_SPECIFIED(nodeGroup.getName());
}
if (!enumRoles.contains(HadoopRole.CUSTOMIZED_ROLE)) {
logger.info("Sorting roles name based on role dependency and relationship with HDFS");
Collections.sort(roles, new RoleComparactor());
nodeGroup.setRoles(roles);
}
}
}
private void addTempFSServerRole(ClusterBlueprint blueprint) {
Set<String> referencedNodeGroups = new HashSet<String>();
for (NodeGroupInfo group : blueprint.getNodeGroups()) {
if (DatastoreType.TEMPFS.name().equalsIgnoreCase(group.getStorageType())) {
PlacementPolicy policies = group.getPlacement();
if (policies != null) {
List<GroupAssociation> associons = policies.getGroupAssociations();
if (associons != null) {
for (GroupAssociation a : associons) {
referencedNodeGroups.add(a.getReference());
}
}
}
}
}
for (NodeGroupInfo group : blueprint.getNodeGroups()) {
if (referencedNodeGroups.contains(group.getName())
&& !group.getRoles().contains(HadoopRole.TEMPFS_SERVER_ROLE.toString())) {
group.getRoles().add(0, HadoopRole.TEMPFS_SERVER_ROLE.toString());
}
}
}
private void setExternalHDFSFromConf(ClusterBlueprint blueprint) {
boolean computeOnly = true;
for (NodeGroupInfo group : blueprint.getNodeGroups()) {
if (group.getRoles().contains(
HadoopRole.HADOOP_NAMENODE_ROLE.toString()) || group
.getRoles().contains(HadoopRole.MAPR_CLDB_ROLE.toString())) {
computeOnly = false;
}
}
if (computeOnly && blueprint.getConfiguration() != null) {
Map conf = blueprint.getConfiguration();
Map hadoopConf = (Map) conf.get("hadoop");
if (hadoopConf != null) {
Map coreSiteConf = (Map) hadoopConf.get("core-site.xml");
if (coreSiteConf != null) {
String hdfs = (String) coreSiteConf.get("fs.default.name");
if (hdfs != null && !hdfs.isEmpty()) {
logger.info("Update external HDFS URL to make spec consistent with hadoop configuration");
blueprint.setExternalHDFS(hdfs);
}
}
}
}
}
private void setExternalMapReduceFromConf(ClusterBlueprint blueprint) {
ServiceType type = getMapReduceType(blueprint);
if (blueprint.getConfiguration() != null) {
Map conf = blueprint.getConfiguration();
Map hadoopConf = (Map) conf.get("hadoop");
if (hadoopConf != null) {
Map coreSiteConf = null;
String mapreduce = "";
if (type == null || type.equals(ServiceType.MAPRED)) {
coreSiteConf = (Map) hadoopConf.get("mapred-site.xml");
if (coreSiteConf != null) {
mapreduce = (String) coreSiteConf.get("mapred.job.tracker");
}
} else {
coreSiteConf = (Map) hadoopConf.get("yarn-site.xml");
if (coreSiteConf != null) {
mapreduce =
(String) coreSiteConf
.get("yarn.resourcemanager.hostname");
}
}
if (mapreduce != null && !mapreduce.isEmpty()) {
logger.info("Update external MapReduce URL to make spec consistent with hadoop configuration");
blueprint.setExternalMapReduce(mapreduce);
}
}
}
}
private void setHadoopConfFromExternalMapReduce(ClusterBlueprint blueprint) {
if (validator.hasMapreduceConfigured(blueprint)) {
changeNodeGroupMapReduceUrl(blueprint.getNodeGroups(),
blueprint.getExternalMapReduce());
changeClusterMapReduceUrl(blueprint);
}
}
@SuppressWarnings("unchecked")
private void changeClusterMapReduceUrl(ClusterBlueprint blueprint) {
Map<String, Object> conf = blueprint.getConfiguration();
if (conf == null) {
conf = new HashMap<String, Object>();
blueprint.setConfiguration(conf);
}
Map<String, Object> hadoopConf = (Map<String, Object>) conf.get("hadoop");
if (hadoopConf == null) {
hadoopConf = new HashMap<String, Object>();
conf.put("hadoop", hadoopConf);
}
ServiceType type = getMapReduceType(blueprint);
Map<String, Object> coreSiteConf = null;
if (type == null || type.equals(ServiceType.MAPRED)) {
coreSiteConf = (Map<String, Object>) hadoopConf.get("mapred-site.xml");
if (coreSiteConf == null) {
coreSiteConf = new HashMap<String, Object>();
hadoopConf.put("mapred-site.xml", coreSiteConf);
}
coreSiteConf.put("mapred.job.tracker",
blueprint.getExternalMapReduce());
}
if (type == null || type.equals(ServiceType.YARN)){
coreSiteConf = (Map<String, Object>) hadoopConf.get("yarn-site.xml");
if (coreSiteConf == null) {
coreSiteConf = new HashMap<String, Object>();
hadoopConf.put("yarn-site.xml", coreSiteConf);
}
coreSiteConf.put("yarn.resourcemanager.hostname",
blueprint.getExternalMapReduce());
}
}
private void changeNodeGroupMapReduceUrl(List<NodeGroupInfo> nodeGroups,
String externalHDFS) {
if (nodeGroups == null || nodeGroups.isEmpty()) {
return;
}
String[] propertyPath = null;
Map<String, Object> confTmp = null;
for (NodeGroupInfo nodeGroup : nodeGroups) {
Map<String, Object> conf = nodeGroup.getConfiguration();
ServiceType type = getMapReduceType(nodeGroup);
if (conf != null) {
confTmp =conf;
if (type == null || type.equals(ServiceType.MAPRED)) {
propertyPath = new String[] { "hadoop", "mapred-site.xml", "mapred.job.tracker" };
setPropertyOfConfiguration(conf, propertyPath, externalHDFS);
}
conf = confTmp;
if (type == null || type.equals(ServiceType.YARN)) {
propertyPath = new String[] { "hadoop", "yarn-site.xml", "yarn.resourcemanager.hostname" };
setPropertyOfConfiguration(conf, propertyPath, externalHDFS);
}
}
}
}
private ServiceType getMapReduceType(ClusterBlueprint blueprint) {
ServiceType type = null;
List<String> roles = new ArrayList<String>();
for (NodeGroupInfo group : blueprint.getNodeGroups()) {
roles.addAll(group.getRoles());
}
if (roles.contains(HadoopRole.HADOOP_NODEMANAGER_ROLE.toString())) {
type = ServiceType.YARN;
} else if (roles.contains(HadoopRole.HADOOP_TASKTRACKER.toString())) {
type = ServiceType.MAPRED;
}
return type;
}
private ServiceType getMapReduceType(NodeGroupInfo group) {
ServiceType type = null;
List<String> roles = new ArrayList<String>();
roles.addAll(group.getRoles());
if (roles.contains(HadoopRole.HADOOP_NODEMANAGER_ROLE.toString())) {
type = ServiceType.YARN;
} else if (roles.contains(HadoopRole.HADOOP_TASKTRACKER.toString())) {
type = ServiceType.MAPRED;
}
return type;
}
private void setHadoopConfFromExternalHDFS(ClusterBlueprint blueprint) {
if (blueprint.getExternalHDFS() != null) {
if (validator.validateHDFSUrl(blueprint)) {
changeNodeGroupHDFSUrl(blueprint.getNodeGroups(),
blueprint.getExternalHDFS());
changeClusterHDFSUrl(blueprint);
} else {
throw BddException.INVALID_PARAMETER("externalHDFS",
blueprint.getExternalHDFS());
}
}
}
@SuppressWarnings("unchecked")
private void changeClusterHDFSUrl(ClusterBlueprint blueprint) {
Map<String, Object> conf = blueprint.getConfiguration();
if (conf == null) {
conf = new HashMap<String, Object>();
blueprint.setConfiguration(conf);
}
Map<String, Object> hadoopConf = (Map<String, Object>) conf.get("hadoop");
if (hadoopConf == null) {
hadoopConf = new HashMap<String, Object>();
conf.put("hadoop", hadoopConf);
}
Map<String, Object> coreSiteConf =
(Map<String, Object>) hadoopConf.get("core-site.xml");
if (coreSiteConf == null) {
coreSiteConf = new HashMap<String, Object>();
hadoopConf.put("core-site.xml", coreSiteConf);
}
coreSiteConf.put("fs.default.name", blueprint.getExternalHDFS());
}
private void changeNodeGroupHDFSUrl(List<NodeGroupInfo> nodeGroups,
String externalHDFS) {
if (nodeGroups == null || nodeGroups.isEmpty()) {
return;
}
String[] propertyPath =
new String[] { "hadoop", "core-site.xml", "fs.default.name" };
for (NodeGroupInfo nodeGroup : nodeGroups) {
Map<String, Object> conf = nodeGroup.getConfiguration();
if (conf != null) {
this.setPropertyOfConfiguration(conf, propertyPath, externalHDFS);
}
}
}
@SuppressWarnings("unchecked")
private void setPropertyOfConfiguration(Map<String, Object> conf,
String[] propertyPath, String value) {
for (String configKeyName : propertyPath) {
if (configKeyName.equals(propertyPath[propertyPath.length - 1])) {
if (conf.get(configKeyName) != null) {
conf.put(configKeyName, value);
}
} else {
conf = (Map<String, Object>) conf.get(configKeyName);
if (conf == null) {
break;
}
}
}
}
}