/***************************************************************************
* 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.sp;
import com.vmware.bdd.entity.NicEntity;
import com.vmware.bdd.entity.NodeEntity;
import com.vmware.bdd.exception.BddException;
import com.vmware.bdd.manager.intf.IClusterEntityManager;
import com.vmware.bdd.service.impl.ClusterUpgradeService;
import com.vmware.bdd.utils.CommonUtil;
import com.vmware.bdd.utils.Constants;
import com.vmware.bdd.utils.VcVmUtil;
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Transactional;
import com.vmware.aurora.composition.IPrePostPowerOn;
import com.vmware.aurora.vc.VcCache;
import com.vmware.aurora.vc.VcVirtualMachine;
import com.vmware.aurora.vc.vcservice.VcContext;
import com.vmware.aurora.vc.vcservice.VcSession;
import java.util.Set;
public class StartVmPostPowerOn implements IPrePostPowerOn {
private static final Logger logger = Logger.getLogger(StartVmPostPowerOn.class);
private static long checkPeriod = 10 * 1000; // 10 seconds
private String vmId;
private VcVirtualMachine vm;
private long timeout;
private Set<String> portGroups;
private IClusterEntityManager clusterEntityMgr;
/**
* After a VM is powered on, wait for the guest information to be
* available at most for <tt>timeout</tt> in seconds, and retrieve the
* guest information.
*
* @param portGroups
* @param timeoutInSeconds
*/
public StartVmPostPowerOn(Set<String> portGroups, int timeoutInSeconds) {
this.portGroups = portGroups;
this.timeout = timeoutInSeconds * 1000L;
}
public StartVmPostPowerOn(Set<String> portGroups, int timeoutInSeconds, IClusterEntityManager clusterEntityMgr) {
this.portGroups = portGroups;
this.timeout = timeoutInSeconds * 1000L;
this.clusterEntityMgr = clusterEntityMgr;
}
@Override
public Void call() throws Exception {
long start = System.currentTimeMillis();
vm = VcCache.getIgnoreMissing(vmId);
while (System.currentTimeMillis() - start < timeout) {
boolean stop = VcContext.inVcSessionDo(new VcSession<Boolean>() {
@Override
protected Boolean body() throws Exception {
if (vm != null && vm.isPoweredOn()) {
return false;
} else {
// stop waiting, since vm is not found
logger.info("vm is not found or is powered off in VC, " + "stop waiting for ip address.");
return true;
}
}
});
// check if all ipaddresses for portGroups are valid
int found = 0;
for (String pgName : portGroups) {
String ip = VcVmUtil.getIpAddressOfPortGroup(vm, pgName, false);
if (!ip.equals(Constants.NULL_IPV4_ADDRESS)) {
logger.info("got one ip, vm: " + vm.getName() + ", portgroup: " + pgName + ", ip: " + ip);
found += 1;
}
}
if (found == portGroups.size()) {
break;
}
if (stop) {
break;
}
Thread.sleep(checkPeriod);
}
if (clusterEntityMgr != null) {
NodeEntity node = clusterEntityMgr.getNodeWithNicsByMobId(vmId);
for (NicEntity nicEntity : node.getNics()) {
VcVmUtil.populateNicInfo(nicEntity, node.getMoId(), nicEntity.getNetworkEntity().getPortGroup());
}
upgradeNode(node);
}
return null;
}
@Override
public void setVm(VcVirtualMachine vm) {
vmId = vm.getId();
this.vm = vm;
}
@Override
public VcVirtualMachine getVm() {
return vm;
}
public String getVmId() {
return vmId;
}
public void setVmId(String vmId) {
this.vmId = vmId;
}
private void upgradeNode(NodeEntity node) {
String serverVersion = clusterEntityMgr.getServerVersion();
String vmName = node.getVmName();
if (node.needUpgrade(serverVersion) && node.canBeUpgrade()) {
logger.debug("vm " + vmName + "is going to upgrade");
clusterEntityMgr.updateNodeActionForUpgrade(node, Constants.NODE_ACTION_UPGRADING);
NodeUpgradeSP nodeUpgrade = new NodeUpgradeSP(node, serverVersion);
try {
nodeUpgrade.call();
updateNodeData(node);
} catch (Exception e) {
updateNodeData(node, false , e.getMessage());
throw BddException.UPGRADE(e, e.getMessage());
}
}
}
private void updateNodeData(NodeEntity node) {
updateNodeData(node, true, null);
}
@Transactional
private void updateNodeData(NodeEntity node, boolean upgraded, String errorMessage) {
node = clusterEntityMgr.getNodeWithNicsByMobId(node.getMoId());
String serverVersion = clusterEntityMgr.getServerVersion();
String nodeVmName = node.getVmName();
if (upgraded) {
logger.info("Successfully upgrade cluster node " + nodeVmName);
node.setVersion(serverVersion);
node.setAction(Constants.NODE_ACTION_UPGRADE_SUCCEED);
node.setActionFailed(false);
node.setErrMessage(null);
} else {
logger.error("Failed to upgrade cluster node " + nodeVmName);
node.setAction(Constants.NODE_ACTION_UPGRADE_FAILED);
node.setActionFailed(true);
String errorTimestamp = CommonUtil.getCurrentTimestamp();
String[] messages = errorMessage.split(":");
if (messages != null && messages.length > 0) {
node.setErrMessage(errorTimestamp + " " + messages[messages.length-1]);
} else {
node.setErrMessage(errorTimestamp + " " + "Upgrading node " + nodeVmName + " failed.");
}
}
clusterEntityMgr.update(node);
}
}