/***************************************************************************
* 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.service.job.software.external;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.vmware.bdd.utils.JobUtils;
import org.apache.log4j.Logger;
import org.springframework.batch.core.scope.context.ChunkContext;
import com.vmware.aurora.util.AuAssert;
import com.vmware.bdd.apitypes.NodeStatus;
import com.vmware.bdd.manager.intf.ILockedClusterEntityManager;
import com.vmware.bdd.service.job.JobConstants;
import com.vmware.bdd.service.job.StatusUpdater;
import com.vmware.bdd.service.job.TrackableTasklet;
import com.vmware.bdd.service.job.software.ISoftwareManagementTask;
import com.vmware.bdd.service.job.software.ManagementOperation;
import com.vmware.bdd.software.mgmt.plugin.intf.SoftwareManager;
import com.vmware.bdd.software.mgmt.plugin.model.ClusterBlueprint;
import com.vmware.bdd.software.mgmt.plugin.model.NodeGroupInfo;
import com.vmware.bdd.software.mgmt.plugin.model.NodeInfo;
import com.vmware.bdd.software.mgmt.plugin.monitor.ClusterReport;
import com.vmware.bdd.software.mgmt.plugin.monitor.ClusterReportQueue;
import com.vmware.bdd.utils.CommonUtil;
/**
* Author: Xiaoding Bian
* Date: 6/11/14
* Time: 2:58 PM
*/
public class ExternalManagementTask implements ISoftwareManagementTask {
private static final Logger logger = Logger.getLogger(ExternalManagementTask.class);
private String targetName;
private ManagementOperation managementOperation;
private ClusterBlueprint clusterBlueprint;
private StatusUpdater statusUpdater;
private ILockedClusterEntityManager lockedClusterEntityManager;
private SoftwareManager softwareManager;
private ChunkContext chunkContext;
public ExternalManagementTask(String targetName, ManagementOperation managementOperation,
ClusterBlueprint clusterBlueprint, StatusUpdater statusUpdater,
ILockedClusterEntityManager lockedClusterEntityManager, SoftwareManager softwareManager,
ChunkContext chunkContext) {
this.targetName = targetName;
this.managementOperation = managementOperation;
this.clusterBlueprint = clusterBlueprint;
this.statusUpdater = statusUpdater;
this.lockedClusterEntityManager = lockedClusterEntityManager;
this.softwareManager = softwareManager;
this.chunkContext = chunkContext;
}
@Override
public Map<String, Object> call() throws Exception {
Map<String, Object> result = new HashMap<String, Object>();
ClusterReportQueue queue = new ClusterReportQueue();
Thread progressThread = null;
ExternalProgressMonitor monitor =
new ExternalProgressMonitor(targetName, queue, statusUpdater,
lockedClusterEntityManager);
progressThread = new Thread(monitor, "ProgressMonitor-" + targetName);
progressThread.setDaemon(true);
progressThread.start();
boolean success = false;
boolean force = false;
if (chunkContext != null) {
force = JobUtils.getJobParameterForceClusterOperation(chunkContext);
}
try {
switch(managementOperation) {
case CREATE:
success = softwareManager.createCluster(clusterBlueprint, queue);
break;
case CONFIGURE:
success = softwareManager.reconfigCluster(clusterBlueprint, queue);
break;
case PRE_DESTROY:
if (softwareManager == null) {
logger.warn("Software manager was unavailable when deleting cluster " + clusterBlueprint.getName() + ", will skip it and delete vms forcely");
logger.warn("You may need to delete related resource on software manager server manually.");
success = true;
} else {
//When failed to delete cluster on software side, we will delete node vm in force
try {
softwareManager.onDeleteCluster(clusterBlueprint, queue);
} catch (Exception e) {
String errMsg = "Got exception when AppManager " + softwareManager.getName() + " delete cluster";
logger.error(errMsg, e);
}
success = true;
}
break;
case DESTROY:
success = softwareManager.deleteCluster(clusterBlueprint, queue);
break;
case START:
success = softwareManager.startCluster(clusterBlueprint, queue, force);
break;
case STOP:
success = softwareManager.onStopCluster(clusterBlueprint,queue);
break;
case START_NODES:
List<NodeInfo> nodes = new ArrayList<NodeInfo>();
for (NodeGroupInfo group : clusterBlueprint.getNodeGroups()) {
if (group != null) {
for (NodeInfo node : group.getNodes()) {
if (node.getName().equals(targetName)) {
nodes.add(node);
break;
}
}
if (!nodes.isEmpty()) {
break;
}
}
}
success = softwareManager.startNodes(clusterBlueprint.getName(), nodes, queue);
break;
case QUERY:
ClusterReport report = softwareManager.queryClusterStatus(clusterBlueprint);
queue.addClusterReport(report);
success = true;
break;
case RESIZE:
AuAssert.check(chunkContext != null);
List<String> addedNodes = getResizedVmNames(chunkContext, clusterBlueprint);
success = softwareManager.scaleOutCluster(clusterBlueprint, addedNodes, queue, force);
break;
case EXPAND:
AuAssert.check(chunkContext != null);
List<String> addedNode = getNewNodeGroupVmNames(chunkContext, clusterBlueprint);
success = softwareManager.scaleOutCluster(clusterBlueprint, addedNode, queue, force);
default:
success = true;
}
} catch (Throwable t) {
logger.error(" operation : " + managementOperation.name()
+ " failed on cluster: " + targetName, t);
result.put("errorMessage", t.getMessage());
} finally {
if (progressThread != null) {
monitor.setStop(true); // tell monitor to stop monitoring then the thread will exit
progressThread.interrupt(); // wake it up to stop immediately if it's sleeping
progressThread.join();
}
}
result.put("succeed", success);
if (!success) {
logger.error("command execution failed. " + result.get("errorMessage"));
}
return result;
}
private List<String> getResizedVmNames(ChunkContext chunkContext,
ClusterBlueprint clusterBlueprint) {
String groupName =
TrackableTasklet.getJobParameters(chunkContext).getString(
JobConstants.GROUP_NAME_JOB_PARAM);
long oldInstanceNum =
TrackableTasklet.getJobParameters(chunkContext).getLong(
JobConstants.GROUP_INSTANCE_OLD_NUMBER_JOB_PARAM);
List<String> addedNodeNames = new ArrayList<String>();
for (NodeGroupInfo group : clusterBlueprint.getNodeGroups()) {
if (group.getName().equals(groupName)) {
for (NodeInfo node: group.getNodes()) {
long index = CommonUtil.getVmIndex(node.getName());
if (index < oldInstanceNum) {
continue;
}
if (JobUtils.getJobParameterForceClusterOperation(chunkContext)) {
NodeStatus status = lockedClusterEntityManager.getClusterEntityMgr().findNodeByName(node.getName()).getStatus();
logger.info(String.format("node %1s's status is %2s", node.getName(), status.name()));
if ((status != NodeStatus.VM_READY) && (status != NodeStatus.BOOTSTRAP_FAILED)) {
continue;
}
}
addedNodeNames.add(node.getName());
}
}
}
return addedNodeNames;
}
private List<String> getNewNodeGroupVmNames(ChunkContext chunkContext,
ClusterBlueprint clusterBlueprint) {
List<String> nodeGroupNames = new ArrayList<String>();
String nodeGroupNameList =
TrackableTasklet.getJobParameters(chunkContext).getString(
JobConstants.NEW_NODE_GROUP_LIST_JOB_PARAM);
for (String nodeGroupName : nodeGroupNameList.split(",")){
nodeGroupNames.add(nodeGroupName);
}
logger.info("getNewNodeGroupVmNames===nodeGroupNameList:" + nodeGroupNameList);
for (String nodeName: nodeGroupNames) {
logger.info("AddedNodeNames:" + nodeName);
}
List<String> addedNodeNames = new ArrayList<String>();
for (String groupName : nodeGroupNames) {
for (NodeGroupInfo group : clusterBlueprint.getNodeGroups()) {
if (group.getName().equals(groupName)) {
for (NodeInfo node: group.getNodes()) {
if (JobUtils.getJobParameterForceClusterOperation(chunkContext)) {
NodeStatus status = lockedClusterEntityManager.getClusterEntityMgr().findNodeByName(node.getName()).getStatus();
logger.info(String.format("node %1s's status is %2s", node.getName(), status.name()));
if ((status != NodeStatus.VM_READY) && (status != NodeStatus.BOOTSTRAP_FAILED)) {
continue;
}
}
addedNodeNames.add(node.getName());
}
}
}
}
for (String nodeName: addedNodeNames) {
logger.info("AddedNodeNames:" + nodeName);
}
return addedNodeNames;
}
}