/***************************************************************************
* Copyright (c) 2012-2014 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.Set;
import org.apache.log4j.Logger;
import com.vmware.aurora.vc.VcDatastore;
import com.vmware.aurora.vc.VcHost;
import com.vmware.bdd.apitypes.ClusterCreate;
import com.vmware.bdd.apitypes.NodeGroupCreate;
import com.vmware.bdd.apitypes.StorageRead.DiskType;
import com.vmware.bdd.entity.DiskEntity;
import com.vmware.bdd.entity.NodeEntity;
import com.vmware.bdd.exception.ScaleServiceException;
import com.vmware.bdd.manager.ClusterConfigManager;
import com.vmware.bdd.manager.intf.IClusterEntityManager;
import com.vmware.bdd.service.IScaleService;
import com.vmware.bdd.service.sp.ScaleVMSP;
import com.vmware.bdd.service.utils.VcResourceUtils;
import com.vmware.bdd.utils.VcVmUtil;
/**
* @author Jarred Li
* @version 0.9
* @since 0.9
*
*/
public class ScaleService implements IScaleService {
private static final Logger logger = Logger.getLogger(ScaleService.class);
private IClusterEntityManager clusterEntityMgr;
private ClusterConfigManager clusterConfigMgr;
/**
* @return the clusterEntityMgr
*/
public IClusterEntityManager getClusterEntityMgr() {
return clusterEntityMgr;
}
/**
* @param clusterEntityMgr
* the clusterEntityMgr to set
*/
public void setClusterEntityMgr(IClusterEntityManager clusterEntityMgr) {
this.clusterEntityMgr = clusterEntityMgr;
}
public ClusterConfigManager getClusterConfigMgr() {
return clusterConfigMgr;
}
public void setClusterConfigMgr(ClusterConfigManager clusterConfigMgr) {
this.clusterConfigMgr = clusterConfigMgr;
}
/* (non-Javadoc)
* @see com.vmware.bdd.service.IScaleService#scaleNodeResource(java.lang.String, int, long)
*/
@Override
public boolean scaleNodeResource(String nodeName, int cpuNumber, long memory) {
logger.info("scale node: " + nodeName + ", cpu number: " + cpuNumber
+ ", memory: " + memory);
NodeEntity node = clusterEntityMgr.findNodeByName(nodeName);
DiskEntity swapDisk = findSwapDisk(node);
VcDatastore targetDs = null;
long newSwapSizeInMB = 0;
if (memory > 0) {
newSwapSizeInMB =
(((long) Math.ceil(memory * node.getNodeGroup().getSwapRatio()) + 1023) / 1024) * 1024;
logger.info("new swap disk size(MB): " + newSwapSizeInMB);
targetDs = getTargetDsForSwapDisk(node, swapDisk, newSwapSizeInMB);
}
ScaleVMSP scaleVMSP =
new ScaleVMSP(node.getMoId(), cpuNumber, memory, targetDs,
swapDisk, newSwapSizeInMB);
return VcVmUtil.runSPOnSingleVM(node, scaleVMSP);
}
public DiskEntity findSwapDisk(NodeEntity node) {
DiskEntity swapDisk = null;
Set<DiskEntity> diskEntities = node.getDisks();
for (DiskEntity diskEntity : diskEntities) {
if (diskEntity.getDiskType().equals(DiskType.SWAP_DISK.getType())) {
swapDisk = diskEntity;
break;
}
}
return swapDisk;
}
public VcDatastore getTargetDsForSwapDisk(NodeEntity node,
DiskEntity swapDisk, long newSwapSizeInMB) {
ClusterCreate clusterSpec =
clusterConfigMgr.getClusterConfig(node.getNodeGroup().getCluster()
.getName());
NodeGroupCreate ngSpec =
clusterSpec.getNodeGroup(node.getNodeGroup().getName());
// use current DS if it has enough space
VcDatastore currentDs =
VcResourceUtils.findDSInVcByName(swapDisk.getDatastoreName());
if (!currentDs.isAccessible()) {
throw ScaleServiceException.CURRENT_DATASTORE_UNACCESSIBLE(currentDs
.getName());
}
if ((int) (currentDs.getFreeSpace() >> 20) > newSwapSizeInMB
- swapDisk.getSizeInMB()) {
return currentDs;
}
// else find a valid datastore with largest free space
VcHost locateHost = VcResourceUtils.findHost(node.getHostName());
// swap disk should use image store pattern
String[] dsNamePatterns =
NodeGroupCreate.getImagestoreNamePattern(clusterSpec, ngSpec);
VcDatastore targetDs = null;
for (VcDatastore ds : locateHost.getDatastores()) {
if (!ds.isAccessible()) {
continue;
}
for (String pattern : dsNamePatterns) {
if (ds.getName().matches(pattern)) {
if (targetDs == null
|| targetDs.getFreeSpace() < ds.getFreeSpace()) {
targetDs = ds;
}
break;
}
}
}
if (targetDs != null
&& (int) (targetDs.getFreeSpace() >> 20) > newSwapSizeInMB) {
return targetDs;
}
logger.warn("cannot find a proper datastore to scale up swap disk of vm: "
+ node.getVmName());
return null;
}
/* (non-Javadoc)
* @see com.vmware.bdd.service.IScaleService#getVmOriginalCpuNumber(java.lang.String)
*/
@Override
public int getVmOriginalCpuNumber(String nodeName) {
NodeEntity node = clusterEntityMgr.findNodeByName(nodeName);
return node.getCpuNum();
}
/* (non-Javadoc)
* @see com.vmware.bdd.service.IScaleService#getVmOriginalMemory(java.lang.String)
*/
@Override
public long getVmOriginalMemory(String nodeName) {
NodeEntity node = clusterEntityMgr.findNodeByName(nodeName);
return node.getMemorySize();
}
/* (non-Javadoc)
* @see com.vmware.bdd.service.IScaleService#updateSwapDisk(java.lang.String)
*/
@Override
public void updateSwapDisk(String nodeName) {
logger.info("update swap disk meta data for node: " + nodeName);
NodeEntity node = clusterEntityMgr.findNodeByName(nodeName);
DiskEntity swapDisk = findSwapDisk(node);
VcVmUtil.populateDiskInfo(swapDisk, node.getMoId());
}
}