/***************************************************************************
* Copyright (c) 2014-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.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Transactional;
import com.vmware.aurora.composition.concurrent.ExecutionResult;
import com.vmware.aurora.composition.concurrent.Scheduler;
import com.vmware.bdd.apitypes.NetConfigInfo.NetTrafficType;
import com.vmware.bdd.apitypes.ClusterNetConfigInfo;
import com.vmware.bdd.apitypes.NetworkDnsType;
import com.vmware.bdd.entity.ClusterEntity;
import com.vmware.bdd.entity.NicEntity;
import com.vmware.bdd.entity.NodeEntity;
import com.vmware.bdd.entity.NodeGroupEntity;
import com.vmware.bdd.exception.BddException;
import com.vmware.bdd.manager.HostnameManager;
import com.vmware.bdd.manager.intf.IClusterEntityManager;
import com.vmware.bdd.service.IGenerateHostnameService;
import com.vmware.bdd.service.job.StatusUpdater;
import com.vmware.bdd.service.sp.NoProgressUpdateCallback;
import com.vmware.bdd.service.sp.NodeGenerateHostnameSP;
import com.vmware.bdd.spectypes.NicSpec;
import com.vmware.bdd.utils.CommonUtil;
import com.vmware.bdd.utils.Constants;
import com.vmware.bdd.utils.ScriptForUpdatingEtcHostsGenerator;
public class GenerateHostnameService implements IGenerateHostnameService {
private static final Logger logger = Logger.getLogger(GenerateHostnameService.class);
private IClusterEntityManager clusterEntityMgr;
private String scriptForUpdatingEtcHosts;
@Override
public boolean generateHostnameForNodes(String clusterName, StatusUpdater statusUpdator) {
logger.info("Generate hostname for all nodes of cluster " + clusterName + ".");
ClusterEntity cluster = clusterEntityMgr.findByName(clusterName);
List<NodeEntity> nodes = clusterEntityMgr.findAllNodes(clusterName);
List<Callable<Void>> storeNodeProcedures = new ArrayList<Callable<Void>>();
try {
int needGenerateCount = 0;
for (NetTrafficType netTrafficType : cluster.getNetworkConfigInfo().keySet()) {
for (ClusterNetConfigInfo netConfigInfo : cluster.getNetworkConfigInfo().get(netTrafficType)) {
NetworkDnsType dnsType = netConfigInfo.getDnsType();
if (NetworkDnsType.isOthers(dnsType) || (NetworkDnsType.isNormal(dnsType) && netConfigInfo.getIsGenerateHostname())) {
needGenerateCount += 1;
}
}
}
if (needGenerateCount == 0) {
logger.info("No need to run generate hostname step because the DNS type of all Nics of cluster " + clusterName + " are Dynamic or Normal with isGenerateHostname set to false.");
return true;
}
scriptForUpdatingEtcHosts = generateScriptUpdatingEtcHosts(cluster);
for (NodeEntity node : nodes) {
NodeGenerateHostnameSP nodeGenerateHostnameSP = new NodeGenerateHostnameSP(node, scriptForUpdatingEtcHosts);
storeNodeProcedures.add(nodeGenerateHostnameSP);
}
if (storeNodeProcedures.isEmpty()) {
logger.info("no VM is available. Return directly.");
return true;
}
Callable<Void>[] storeNodeProceduresArray = storeNodeProcedures.toArray(new Callable[0]);
NoProgressUpdateCallback callback = new NoProgressUpdateCallback();
ExecutionResult[] result =
Scheduler
.executeStoredProcedures(
com.vmware.aurora.composition.concurrent.Priority.BACKGROUND,
storeNodeProceduresArray, callback);
boolean success = true;
int total = 0;
for (int i = 0; i < storeNodeProceduresArray.length; i++) {
Throwable nodeGenerateHostnameSPException = result[i].throwable;
NodeGenerateHostnameSP sp = (NodeGenerateHostnameSP) storeNodeProceduresArray[i];
NodeEntity node = sp.getNode();
if (result[i].finished && nodeGenerateHostnameSPException == null) {
updateNodeData(node);
++total;
} else if (nodeGenerateHostnameSPException != null) {
updateNodeData(node, false, nodeGenerateHostnameSPException.getMessage(), CommonUtil.getCurrentTimestamp());
logger.error("Failed to generate hostname for cluster node " + node.getVmName(), nodeGenerateHostnameSPException);
success = false;
}
}
logger.info("Hostname of " + total + " nodes are generated.");
return success;
} catch (InterruptedException e) {
logger.error("error in generate hostname for cluster nodes", e);
throw BddException.FAILED_TO_GENERATE_HOSTNAME(e, e.getMessage());
}
}
@Override
public boolean generateHostnameForNodesFailed(String clusterName, StatusUpdater statusUpdator) {
boolean generateHostnameFailed = false;
List<NodeEntity> nodes = getNodes(clusterName);
for (NodeEntity node : nodes) {
if (Constants.NODE_ACTION_GENERATE_HOSTNAME_FAILED.equals(node.getAction())) {
generateHostnameFailed = true;
break;
}
}
return generateHostnameFailed;
}
private void updateNodeData(NodeEntity node) {
updateNodeData(node, true, null, null);
}
@Transactional
private void updateNodeData(NodeEntity node, boolean generated, String errorMessage, String errorTimestamp) {
node = clusterEntityMgr.getNodeWithNicsByMobId(node.getMoId());
String nodeVmName = node.getVmName();
if (generated) {
logger.info("Successfully generate hostname for cluster node " + nodeVmName);
node.setAction(Constants.NODE_ACTION_GENERATE_HOSTNAME_SUCCEED);
node.setActionFailed(false);
node.setErrMessage(null);
clusterEntityMgr.update(node);
} else {
logger.error("Failed to generate hostname for cluster node " + nodeVmName);
node.setAction(Constants.NODE_ACTION_GENERATE_HOSTNAME_FAILED);
node.setActionFailed(true);
String[] messages = errorMessage.split(":");
if (messages != null && messages.length > 0) {
node.setErrMessage(errorTimestamp + " " + messages[messages.length-1]);
} else {
node.setErrMessage(errorTimestamp + " " + "Generate hostname for node " + nodeVmName + " failed.");
}
clusterEntityMgr.update(node);
}
}
private List<NodeEntity> getNodes(String clusterName) {
return clusterEntityMgr.findAllNodes(clusterName);
}
public IClusterEntityManager getClusterEntityMgr() {
return clusterEntityMgr;
}
public void setClusterEntityMgr(IClusterEntityManager clusterEntityMgr) {
this.clusterEntityMgr = clusterEntityMgr;
}
private String generateScriptUpdatingEtcHosts(ClusterEntity cluster) {
String hostsContent = "";
for (NodeGroupEntity nodeGroup : cluster.getNodeGroups()) {
for (NodeEntity node : nodeGroup.getNodes()) {
Map<NetTrafficType, List<ClusterNetConfigInfo>> networkConfigInfo = node.getNodeGroup().getCluster().getNetworkConfigInfo();
Set<NicEntity> nics = node.getNics();
for (NicEntity nic : nics) {
for (NicSpec.NetTrafficDefinition netTrafficDefinition: nic.getNetTrafficDefs()) {
List<ClusterNetConfigInfo> netConfigInfos = networkConfigInfo.get(netTrafficDefinition.getTrafficType());
for (ClusterNetConfigInfo netConfigInfo : netConfigInfos) {
if (NetworkDnsType.isOthers(netConfigInfo.getDnsType())
|| (NetworkDnsType.isNormal(netConfigInfo.getDnsType()) && netConfigInfo.getIsGenerateHostname())) {
String hostname = HostnameManager.generateHostname(node, nic);
hostsContent += nic.getIpv4Address() + ":" + hostname + ",";
}
}
}
}
}
}
ScriptForUpdatingEtcHostsGenerator scriptForUpdatingEtcHostsGenerator = new ScriptForUpdatingEtcHostsGenerator();
String scriptForUpdatingEtcHosts = scriptForUpdatingEtcHostsGenerator.generateScriptForUpdatingEtcHosts(cluster.getName(), hostsContent);
return scriptForUpdatingEtcHosts;
}
}