Bug 7845 - Productize DeploymentPlanner

Bug 7723 - merge or re-write host tagging into master / 2.2
Bug 7627 - Need more logging for Allocators
Bug 8317 - Add better resource allocation failure messages

Changes for Deployment Planner to use host and storagePool allocators to find deployment destination.
Also has the changes for host tag feature.
Improved the logging for allocators.
This commit is contained in:
prachi 2011-02-25 18:55:12 -08:00
parent 2a95a95d18
commit 889827b63a
57 changed files with 1800 additions and 744 deletions

View File

@ -193,5 +193,6 @@ public class ApiConstants {
public static final String AVAILABILITY = "availability";
public static final String NETWORKRATE = "networkrate";
public static final String GUEST_IP_TYPE = "guestiptype";
public static final String HOST_TAGS = "hosttags";
}

View File

@ -15,8 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.api.commands;
package com.cloud.api.commands;
import java.util.ArrayList;
import java.util.List;
@ -34,8 +34,8 @@ import com.cloud.host.Host;
import com.cloud.user.Account;
@Implementation(description="Adds a new host.", responseObject=HostResponse.class)
public class AddHostCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(AddHostCmd.class.getName());
public class AddHostCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(AddHostCmd.class.getName());
private static final String s_name = "addhostresponse";
@ -67,6 +67,8 @@ public class AddHostCmd extends BaseCmd {
@Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=true, description="hypervisor type of the host")
private String hypervisor;
@Parameter(name=ApiConstants.HOST_TAGS, type=CommandType.LIST, collectionType=CommandType.STRING, description="list of tags to be added to the host")
private List<String> hostTags;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
@ -103,6 +105,10 @@ public class AddHostCmd extends BaseCmd {
public String getHypervisor() {
return hypervisor;
}
public List<String> getHostTags() {
return hostTags;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
@ -141,5 +147,5 @@ public class AddHostCmd extends BaseCmd {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage());
}
}
}
}
}

View File

@ -65,6 +65,10 @@ public class CreateServiceOfferingCmd extends BaseCmd {
@Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="the ID of the containing domain, null for public offerings")
private Long domainId;
@Parameter(name=ApiConstants.HOST_TAGS, type=CommandType.STRING, description="the host tag for this service offering.")
private String hostTag;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -105,6 +109,9 @@ public class CreateServiceOfferingCmd extends BaseCmd {
return domainId;
}
public String getHostTag() {
return hostTag;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -141,6 +141,9 @@ public class HostResponse extends BaseResponse {
@SerializedName("jobstatus") @Param(description="shows the current pending asynchronous job status")
private Integer jobStatus;
@SerializedName("hosttags") @Param(description="comma-separated list of tags for the host")
private String hostTags;
@Override
public Long getObjectId() {
return getId();
@ -453,4 +456,12 @@ public class HostResponse extends BaseResponse {
public void setEvents(String events) {
this.events = events;
}
public String getHostTags() {
return hostTags;
}
public void setHostTags(String hostTags) {
this.hostTags = hostTags;
}
}

View File

@ -60,6 +60,9 @@ public class ServiceOfferingResponse extends BaseResponse {
@SerializedName(ApiConstants.DOMAIN) @Param(description="Domain name for the offering")
private String domain;
@SerializedName(ApiConstants.HOST_TAGS) @Param(description="the host tag for the service offering")
private String hostTag;
public Long getId() {
return id;
}
@ -156,6 +159,12 @@ public class ServiceOfferingResponse extends BaseResponse {
this.domain = domain;
}
public String getHostTag() {
return hostTag;
}
public void setHostTag(String hostTag) {
this.hostTag = hostTag;
}
}

View File

@ -35,6 +35,7 @@ public interface Capacity {
public Long getHostOrPoolId();
public long getDataCenterId();
public Long getPodId();
public Long getClusterId();
public long getUsedCapacity();
public long getTotalCapacity();
public short getCapacityType();

View File

@ -47,6 +47,11 @@ public class DeployDestination {
_host = host;
}
public DeployDestination(DataCenter dc, Pod pod, Cluster cluster, Host host, Map<Volume, StoragePool> storage) {
this(dc,pod,cluster,host);
_storage = storage;
}
public DeployDestination() {
}
@ -84,6 +89,22 @@ public class DeployDestination {
@Override
public String toString() {
return new StringBuilder("Dest[").append(_dc.getId()).append("-").append(_pod.getId()).append("-").append(_cluster.getId()).append("-").append(_host.getId()).append("]").toString();
StringBuilder destination = new StringBuilder("Dest[Zone(Id)-Pod(Id)-Cluster(Id)-Host(Id)-Storage(Volume(Id|Type-->Pool(Id))] : Dest[");
destination.append("Zone(").append(_dc.getId()).append(")").append("-");
destination.append("Pod(").append(_pod.getId()).append(")").append("-");
destination.append("Cluster(").append(_cluster.getId()).append(")").append("-");
destination.append("Host(").append(_host.getId()).append(")").append("-");
destination.append("Storage(");
if(_storage != null){
String storageStr = "";
for(Volume vol : _storage.keySet()){
if(!storageStr.equals("")){
storageStr = storageStr + ", ";
}
storageStr = storageStr + "Volume(" + vol.getId() + "|"+ vol.getVolumeType().name() + "-->Pool("+_storage.get(vol).getId()+")";
}
destination.append(storageStr);
}
return destination.append(")]").toString();
}
}

View File

@ -45,11 +45,21 @@ public interface DeploymentPlanner extends Adapter {
boolean check(VirtualMachineProfile<? extends VirtualMachine> vm, DeploymentPlan plan, DeployDestination dest, ExcludeList exclude);
public static class ExcludeList {
Set<Long> _dcIds;
Set<Long> _podIds;
Set<Long> _clusterIds;
Set<Long> _hostIds;
Set<Long> _poolIds;
private Set<Long> _dcIds;
private Set<Long> _podIds;
private Set<Long> _clusterIds;
private Set<Long> _hostIds;
private Set<Long> _poolIds;
public ExcludeList(){
}
public ExcludeList(Set<Long> _dcIds, Set<Long> _podIds, Set<Long> _clusterIds, Set<Long> _hostIds, Set<Long> _poolIds){
this._dcIds = _dcIds;
this._podIds = _podIds;
this._clusterIds = _clusterIds;
this._poolIds = _poolIds;
}
public boolean add(InsufficientCapacityException e) {
Class<?> scope = e.getScope();
@ -180,5 +190,45 @@ public interface DeploymentPlanner extends Adapter {
return false;
}
public boolean shouldAvoid(StoragePool pool) {
if (_dcIds != null && _dcIds.contains(pool.getDataCenterId())) {
return true;
}
if (_podIds != null && _podIds.contains(pool.getPodId())) {
return true;
}
if (_clusterIds != null && _clusterIds.contains(pool.getClusterId())) {
return true;
}
if (_poolIds != null && _poolIds.contains(pool.getId())) {
return true;
}
return false;
}
public Set<Long> getDataCentersToAvoid(){
return _dcIds;
}
public Set<Long> getPodsToAvoid(){
return _podIds;
}
public Set<Long> getClustersToAvoid(){
return _clusterIds;
}
public Set<Long> getHostsToAvoid(){
return _hostIds;
}
public Set<Long> getPoolsToAvoid(){
return _poolIds;
}
}
}

View File

@ -72,6 +72,11 @@ public interface ServiceOffering {
*/
boolean getUseLocalStorage();
Long getDomainId();
Long getDomainId();
/**
* @return tag that should be present on the host needed, optional parameter
*/
String getHostTag();
}

View File

@ -42,6 +42,9 @@ public class CapacityVO implements Capacity {
@Column(name="pod_id")
private Long podId;
@Column(name="cluster_id")
private Long clusterId;
@Column(name="used_capacity")
private long usedCapacity;
@ -56,10 +59,11 @@ public class CapacityVO implements Capacity {
public CapacityVO() {}
public CapacityVO(Long hostId, long dataCenterId, Long podId, long usedCapacity, long totalCapacity, short capacityType) {
public CapacityVO(Long hostId, long dataCenterId, Long podId, Long clusterId, long usedCapacity, long totalCapacity, short capacityType) {
this.hostOrPoolId = hostId;
this.dataCenterId = dataCenterId;
this.podId = podId;
this.podId = podId;
this.clusterId = clusterId;
this.usedCapacity = usedCapacity;
this.totalCapacity = totalCapacity;
this.capacityType = capacityType;
@ -92,7 +96,16 @@ public class CapacityVO implements Capacity {
}
public void setPodId(long podId) {
this.podId = new Long(podId);
}
}
@Override
public Long getClusterId() {
return clusterId;
}
public void setClusterId(long clusterId) {
this.clusterId = new Long(clusterId);
}
@Override
public long getUsedCapacity() {
return usedCapacity;

View File

@ -0,0 +1,47 @@
package com.cloud.host;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="host_tags")
public class HostTagVO {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private long id;
@Column(name="host_id")
private long hostId;
@Column(name="tag")
private String tag;
protected HostTagVO() {
}
public HostTagVO(long hostId, String tag) {
this.hostId = hostId;
this.tag = tag;
}
public long getHostId() {
return hostId;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public long getId() {
return id;
}
}

View File

@ -18,6 +18,7 @@
package com.cloud.host;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.persistence.Column;
@ -131,7 +132,13 @@ public class HostVO implements Host {
// Call host dao to load it.
@Transient
Map<String, String> details;
// This is a delayed load value. If the value is null,
// then this field has not been loaded yet.
// Call host dao to load it.
@Transient
List<String> hostTags;
@Override
public String getStorageIpAddressDeux() {
return storageIpAddressDeux;
@ -274,6 +281,14 @@ public class HostVO implements Host {
public void setDetails(Map<String, String> details) {
this.details = details;
}
public List<String> getHostTags() {
return hostTags;
}
public void setHostTags(List<String> hostTags) {
this.hostTags = hostTags;
}
@Column(name="data_center_id", nullable=false)
private long dataCenterId;

View File

@ -33,6 +33,7 @@ import javax.persistence.TemporalType;
import com.cloud.async.AsyncInstanceCreateStatus;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.GenericDao;
@Entity
@ -450,4 +451,18 @@ public class VolumeVO implements Volume {
public void setChainInfo(String chainInfo) {
this.chainInfo = chainInfo;
}
@Override
public int hashCode() {
return NumbersUtil.hash(id);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof VolumeVO) {
return id == ((VolumeVO)obj).id;
} else {
return false;
}
}
}

View File

@ -153,6 +153,8 @@ public interface AgentManager extends Manager {
Long getGuestOSCategoryId(long hostId);
String getHostTags(long hostId);
/**
* Find a host based on the type needed, data center to deploy in, pod
* to deploy in, service offering, template, and list of host to avoid.
@ -220,7 +222,7 @@ public interface AgentManager extends Manager {
public boolean executeUserRequest(long hostId, Event event) throws AgentUnavailableException;
public boolean reconnect(final long hostId) throws AgentUnavailableException;
public List<HostVO> discoverHosts(Long dcId, Long podId, Long clusterId, String clusterName, String url, String username, String password, String hypervisor)
public List<HostVO> discoverHosts(Long dcId, Long podId, Long clusterId, String clusterName, String url, String username, String password, String hypervisor, List<String> hostTags)
throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
Answer easySend(Long hostId, Command cmd, int timeout);

View File

@ -109,6 +109,7 @@ import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.UnsupportedVersionException;
import com.cloud.ha.HighAvailabilityManager;
import com.cloud.ha.HighAvailabilityManager.WorkType;
@ -157,6 +158,7 @@ import com.cloud.uservm.UserVm;
import com.cloud.utils.ActionDelegate;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.UriUtils;
import com.cloud.utils.component.Adapters;
import com.cloud.utils.component.ComponentLocator;
@ -178,6 +180,7 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachineProfileImpl;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.host.dao.HostTagsDao;
/**
* Implementation of the Agent Manager. This class controls the connection to
@ -254,7 +257,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
protected ClusterDao _clusterDao = null;
@Inject
protected ClusterDetailsDao _clusterDetailsDao = null;
@Inject
protected HostTagsDao _hostTagsDao = null;
@Inject(adapter = DeploymentPlanner.class)
private Adapters<DeploymentPlanner> _planners;
@ -516,8 +521,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
}
} catch (InsufficientServerCapacityException e) {
}
}
}
s_logger.warn("findHost() could not find a non-null host.");
@ -560,12 +564,12 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
}
protected AgentAttache handleDirectConnect(ServerResource resource,
StartupCommand[] startup, Map<String, String> details, boolean old)
StartupCommand[] startup, Map<String, String> details, boolean old, List<String> hostTags)
throws ConnectionException {
if (startup == null) {
return null;
}
HostVO server = createHost(startup, resource, details, old);
HostVO server = createHost(startup, resource, details, old, hostTags);
if (server == null) {
return null;
}
@ -705,7 +709,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
if (resources != null) {
for (Map.Entry<? extends ServerResource, Map<String, String>> entry : resources.entrySet()) {
ServerResource resource = entry.getKey();
AgentAttache attache = simulateStart(resource, entry.getValue(), true);
AgentAttache attache = simulateStart(resource, entry.getValue(), true, null);
if (attache != null) {
hosts.add(_hostDao.findById(attache.getId()));
}
@ -756,8 +760,10 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
if (clusterName == null && clusterId == null) {
clusterName = "Standalone-" + url;
}
List<String> hostTags = cmd.getHostTags();
return discoverHosts(dcId, podId, clusterId, clusterName, url,
username, password, cmd.getHypervisor());
username, password, cmd.getHypervisor(), hostTags);
}
@Override
@ -767,13 +773,13 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
Long dcId = cmd.getZoneId();
String url = cmd.getUrl();
return discoverHosts(dcId, null, null, null, url, null, null,
"SecondaryStorage");
"SecondaryStorage", null);
}
@Override
public List<HostVO> discoverHosts(Long dcId, Long podId, Long clusterId,
String clusterName, String url, String username, String password,
String hypervisorType) throws IllegalArgumentException,
String hypervisorType, List<String> hostTags) throws IllegalArgumentException,
DiscoveryException, InvalidParameterValueException {
URI uri = null;
@ -904,7 +910,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
return null;
}
AgentAttache attache = simulateStart(resource,
entry.getValue(), true);
entry.getValue(), true, hostTags);
if (attache != null) {
hosts.add(_hostDao.findById(attache.getId()));
}
@ -1703,7 +1709,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
}
protected AgentAttache simulateStart(ServerResource resource,
Map<String, String> details, boolean old)
Map<String, String> details, boolean old, List<String> hostTags)
throws IllegalArgumentException {
StartupCommand[] cmds = resource.initialize();
if (cmds == null) {
@ -1718,7 +1724,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
// .toString());
}
try {
attache = handleDirectConnect(resource, cmds, details, old);
attache = handleDirectConnect(resource, cmds, details, old, hostTags);
} catch (IllegalArgumentException ex) {
s_logger.warn("Unable to connect due to ", ex);
throw ex;
@ -1840,6 +1846,16 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
}
}
@Override
public String getHostTags(long hostId){
List<String> hostTags = _hostTagsDao.gethostTags(hostId);
if (hostTags == null) {
return null;
} else {
return StringUtils.listToCsvTags(hostTags);
}
}
@Override
public String getName() {
return _name;
@ -2302,13 +2318,13 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
}
}
AgentAttache attache = simulateStart(resource, hostDetails, true);
AgentAttache attache = simulateStart(resource, hostDetails, true, null);
return _hostDao.findById(attache.getId());
}
public HostVO createHost(final StartupCommand startup,
ServerResource resource, Map<String, String> details,
boolean directFirst) throws IllegalArgumentException {
boolean directFirst, List<String> hostTags) throws IllegalArgumentException {
Host.Type type = null;
if (startup instanceof StartupStorageCommand) {
@ -2374,7 +2390,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
}
server.setDetails(details);
server.setHostTags(hostTags);
updateHost(server, startup, type, _nodeId);
if (resource != null) {
server.setResource(resource.getClass().getName());
@ -2425,9 +2442,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
public HostVO createHost(final StartupCommand[] startup,
ServerResource resource, Map<String, String> details,
boolean directFirst) throws IllegalArgumentException {
boolean directFirst, List<String> hostTags) throws IllegalArgumentException {
StartupCommand firstCmd = startup[0];
HostVO result = createHost(firstCmd, resource, details, directFirst);
HostVO result = createHost(firstCmd, resource, details, directFirst, hostTags);
if (result == null) {
return null;
}
@ -2437,7 +2454,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
public AgentAttache handleConnect(final Link link,
final StartupCommand[] startup) throws IllegalArgumentException,
ConnectionException {
HostVO server = createHost(startup, null, null, false);
HostVO server = createHost(startup, null, null, false, null);
if (server == null) {
return null;
}
@ -2776,12 +2793,12 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
StartupStorageCommand ssCmd = (StartupStorageCommand) startup;
if (ssCmd.getResourceType() == Storage.StorageResourceType.STORAGE_HOST) {
CapacityVO capacity = new CapacityVO(server.getId(),
server.getDataCenterId(), server.getPodId(), 0L,
server.getDataCenterId(), server.getPodId(), server.getClusterId(),0L,
server.getTotalSize(), CapacityVO.CAPACITY_TYPE_STORAGE);
_capacityDao.persist(capacity);
capacity = new CapacityVO(server.getId(),
server.getDataCenterId(), server.getPodId(), 0L,
server.getDataCenterId(), server.getPodId(), server.getClusterId(), 0L,
server.getTotalSize() * _overProvisioningFactor,
CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED);
_capacityDao.persist(capacity);
@ -2824,7 +2841,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
CapacityVO capacity = new CapacityVO(
server.getId(),
server.getDataCenterId(),
server.getPodId(),
server.getPodId(),
server.getClusterId(),
0L,
(long) (server.getCpus().longValue()
* server.getSpeed().longValue() * _cpuOverProvisioningFactor),
@ -2866,7 +2884,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
_capacityDao.update(CapacityVOMem.getId(), CapacityVOMem);
} else {
CapacityVO capacity = new CapacityVO(server.getId(),
server.getDataCenterId(), server.getPodId(), 0L,
server.getDataCenterId(), server.getPodId(), server.getClusterId(), 0L,
server.getTotalMemory(),
CapacityVO.CAPACITY_TYPE_MEMORY);
_capacityDao.persist(capacity);
@ -2927,7 +2945,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory,
s_logger.debug("Simulating start for resource "
+ resource.getName() + " id " + id);
}
simulateStart(resource, details, false);
simulateStart(resource, details, false, null);
} catch (Exception e) {
s_logger.warn("Unable to simulate start on resource " + id
+ " name " + resource.getName(), e);

View File

@ -17,21 +17,39 @@
*/
package com.cloud.agent.manager.allocator;
import java.util.Set;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import java.util.List;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.VMTemplateVO;
import com.cloud.uservm.UserVm;
import com.cloud.utils.component.Adapter;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
public interface HostAllocator extends Adapter {
/**
* Checks if the VM can be upgraded to the specified ServiceOffering
* @param UserVm vm
* @param ServiceOffering offering
* @return boolean true if the VM can be upgraded
**/
boolean isVirtualMachineUpgradable(final UserVm vm, final ServiceOffering offering);
Host allocateTo(VirtualMachineProfile<? extends VirtualMachine> vm, ServiceOffering offering, Type type, DataCenterVO dc, HostPodVO pod, Long clusterId, VMTemplateVO template, Set<Host> avoid);
/**
* Determines which physical hosts are suitable to
* allocate the guest virtual machines on
*
* @param VirtualMachineProfile vmProfile
* @param DeploymentPlan plan
* @param Type type
* @param ExcludeList avoid
* @param int returnUpTo (use -1 to return all possible hosts)
* @return List<Host> List of hosts that are suitable for VM allocation
**/
public List<Host> allocateTo(VirtualMachineProfile<?extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo);
}

View File

@ -33,6 +33,8 @@ import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
@ -60,6 +62,7 @@ import com.cloud.vm.dao.ConsoleProxyDao;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.SecondaryStorageVmDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.capacity.CapacityManager;
/**
* An allocator that tries to find a fit on a computing host. This allocator does not care whether or not the host supports routing.
@ -80,134 +83,97 @@ public class FirstFitAllocator implements HostAllocator {
@Inject GuestOSCategoryDao _guestOSCategoryDao = null;
float _factor = 1;
protected String _allocationAlgorithm = "random";
@Inject CapacityManager _capacityMgr;
@Override
public Host allocateTo(VirtualMachineProfile<? extends VirtualMachine> vm, ServiceOffering offering, Type type, DataCenterVO dc,
HostPodVO pod, Long clusterId, VMTemplateVO template,
Set<Host> avoid) {
public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
ExcludeList avoid, int returnUpTo) {
long dcId = plan.getDataCenterId();
long podId = plan.getPodId();
long clusterId = plan.getClusterId();
ServiceOffering offering = vmProfile.getServiceOffering();
VMTemplateVO template = (VMTemplateVO)vmProfile.getTemplate();
if (type == Host.Type.Storage) {
// FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of routing or not
return null;
return new ArrayList<Host>();
}
s_logger.debug("Looking for hosts in dc: " + dc.getId() + " pod:" + pod.getId() + " cluster:" + clusterId);
String hostTag = offering.getHostTag();
if(hostTag != null){
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag);
}else{
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
}
List<HostVO> clusterHosts = _hostDao.listBy(type, clusterId, pod.getId(), dc.getId());
Iterator<HostVO> it = clusterHosts.iterator();
while (it.hasNext()) {
HostVO host = it.next();
if (avoid.contains(host)) {
it.remove();
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Adding host " + host + " as possible pod host");
}
}
}
return allocateTo(offering, template, avoid, clusterHosts);
List<HostVO> clusterHosts = new ArrayList<HostVO>();
if(hostTag != null){
clusterHosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag);
}else{
clusterHosts = _hostDao.listBy(type, clusterId, podId, dcId);
}
return allocateTo(offering, template, avoid, clusterHosts, returnUpTo);
}
protected Host allocateTo(ServiceOffering offering, VMTemplateVO template, Set<Host> avoid, List<HostVO> hosts) {
protected List<Host> allocateTo(ServiceOffering offering, VMTemplateVO template, ExcludeList avoid, List<HostVO> hosts, int returnUpTo) {
if (_allocationAlgorithm.equals("random")) {
// Shuffle this so that we don't check the hosts in the same order.
Collections.shuffle(hosts);
}
if (s_logger.isDebugEnabled()) {
StringBuffer sb = new StringBuffer();
for(Host h : avoid) {
sb.append(h.getName()).append(" ");
}
s_logger.debug("Found " + hosts.size() + " hosts for allocation and a avoid set of [" + sb + "]");
s_logger.debug("FirstFitAllocator has " + hosts.size() + " hosts to check for allocation: "+hosts);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Looking for speed=" + (offering.getCpu() * offering.getSpeed()) + "Mhz, Ram=" + offering.getRamSize());
}
// We will try to reorder the host lists such that we give priority to hosts that have
// the minimums to support a VM's requirements
hosts = prioritizeHosts(template, hosts);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found " + hosts.size() + " hosts for allocation after prioritization");
s_logger.debug("Found " + hosts.size() + " hosts for allocation after prioritization: "+ hosts);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Looking for speed=" + (offering.getCpu() * offering.getSpeed()) + "Mhz, Ram=" + offering.getRamSize());
}
List<Host> suitableHosts = new ArrayList<Host>();
for (HostVO host : hosts) {
if (avoid.contains(host)) {
if(suitableHosts.size() == returnUpTo){
break;
}
if (avoid.shouldAvoid(host)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("host " + host.getName() + " is in avoid set, skip and try other available hosts");
s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() +" is in avoid set, skipping this and trying other available hosts");
}
continue;
}
long usedMemory = 0;
double totalSpeed = 0d;
List<DomainRouterVO> domainRouters = _routerDao.listUpByHostId(host.getId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found " + domainRouters.size() + " router domains on host " + host.getId());
}
for (DomainRouterVO router : domainRouters) {
usedMemory += 0;//FIXME or more like get rid of me router.getRamSize() * 1024L * 1024L;
}
List<ConsoleProxyVO> proxys = _consoleProxyDao.listUpByHostId(host.getId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found " + proxys.size() + " console proxy on host " + host.getId());
}
for(ConsoleProxyVO proxy : proxys) {
usedMemory += 0; // FIXME or get ird of me totally proxy.getRamSize() * 1024L * 1024L;
}
List<SecondaryStorageVmVO> secStorageVms = _secStorgaeVmDao.listUpByHostId(host.getId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found " + secStorageVms.size() + " secondary storage VM on host " + host.getId());
}
for(SecondaryStorageVmVO secStorageVm : secStorageVms) {
usedMemory += 0; // FIXME or get rid of me secStorageVm.getRamSize() * 1024L * 1024L;
}
List<UserVmVO> vms = _vmDao.listUpByHostId(host.getId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found " + vms.size() + " user VM on host " + host.getId());
}
for (UserVmVO vm : vms) {
ServiceOffering so = _offeringDao.findById(vm.getServiceOfferingId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("vm " + vm.getId() + ": speed=" + (so.getCpu() * so.getSpeed()) + "Mhz, RAM=" + so.getRamSize() + "MB");
}
usedMemory += so.getRamSize() * 1024L * 1024L;
totalSpeed += so.getCpu() * (so.getSpeed() * 0.99);
}
if (s_logger.isDebugEnabled()) {
long availableSpeed = (long)(host.getCpus() * host.getSpeed() * _factor);
double desiredSpeed = offering.getCpu() * (offering.getSpeed() * 0.99);
long coreSpeed = host.getSpeed();
s_logger.debug("Host " + host.getId() + ": available speed=" + availableSpeed + "Mhz, core speed=" + coreSpeed + "Mhz, used speed=" + totalSpeed + "Mhz, desired speed=" + desiredSpeed +
"Mhz, desired cores: " + offering.getCpu() + ", available cores: " + host.getCpus() + ", RAM=" + host.getTotalMemory() +
", avail RAM=" + (host.getTotalMemory() - usedMemory) + ", desired RAM=" + (offering.getRamSize() * 1024L * 1024L));
}
boolean numCpusGood = host.getCpus().intValue() >= offering.getCpu();
boolean coreSpeedGood = host.getSpeed().doubleValue() >= (offering.getSpeed() * 0.99);
boolean totalSpeedGood = ((host.getCpus().doubleValue() * host.getSpeed().doubleValue() * _factor) - totalSpeed) >= (offering.getCpu() * (offering.getSpeed() * 0.99));
boolean memoryGood = (host.getTotalMemory() - usedMemory) >= (offering.getRamSize() * 1024L * 1024L);
if (numCpusGood && totalSpeedGood && coreSpeedGood && memoryGood) {
int cpu_requested = offering.getCpu() * offering.getSpeed();
long ram_requested = offering.getRamSize() * 1024L * 1024L;
boolean hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false);
if (numCpusGood && hostHasCapacity) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("found host " + host.getId());
s_logger.debug("Found a suitable host, adding to list: " + host.getId());
}
return host;
suitableHosts.add(host);
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("not using host " + host.getId() + "; numCpusGood: " + numCpusGood + ", coreSpeedGood: " + coreSpeedGood + ", totalSpeedGood: " + totalSpeedGood + ", memoryGood: " + memoryGood);
s_logger.debug("Not using host " + host.getId() + "; numCpusGood: " + numCpusGood + ", host has capacity?" + hostHasCapacity);
}
}
}
return null;
if (s_logger.isDebugEnabled()) {
s_logger.debug("Host Allocator returning "+suitableHosts.size() +" suitable hosts");
}
return suitableHosts;
}
@Override

View File

@ -18,34 +18,31 @@
package com.cloud.agent.manager.allocator.impl;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Local;
import org.apache.log4j.NDC;
import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.VMTemplateVO;
import com.cloud.host.Host.Type;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value={HostAllocator.class})
public class FirstFitRoutingAllocator extends FirstFitAllocator {
@Override
public Host allocateTo(VirtualMachineProfile<? extends VirtualMachine> vm, ServiceOffering offering, Host.Type type, DataCenterVO dc, HostPodVO pod,
Long clusterId, VMTemplateVO template, Set<Host> avoid) {
public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
ExcludeList avoid, int returnUpTo) {
try {
NDC.push("FirstFitRoutingAllocator");
if (type != Host.Type.Routing) {
// FirstFitRoutingAllocator is to find space on routing capable hosts only
return null;
return new ArrayList<Host>();
}
//all hosts should be of type routing anyway.
return super.allocateTo(vm, offering, type, dc, pod, clusterId, template, avoid);
return super.allocateTo(vmProfile, plan, type, avoid, returnUpTo);
} finally {
NDC.pop();
}

View File

@ -17,6 +17,7 @@
*/
package com.cloud.agent.manager.allocator.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -25,10 +26,13 @@ import java.util.Set;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.host.HostVO;
import com.cloud.host.Host.Type;
import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.host.dao.HostDao;
import com.cloud.offering.ServiceOffering;
@ -45,26 +49,60 @@ public class RandomAllocator implements HostAllocator {
private HostDao _hostDao;
@Override
public Host allocateTo(VirtualMachineProfile<? extends VirtualMachine> vm, ServiceOffering offering, Host.Type type, DataCenterVO dc, HostPodVO pod,
Long clusterId, VMTemplateVO template, Set<Host> avoid) {
public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
ExcludeList avoid, int returnUpTo) {
long dcId = plan.getDataCenterId();
long podId = plan.getPodId();
long clusterId = plan.getClusterId();
ServiceOffering offering = vmProfile.getServiceOffering();
List<Host> suitableHosts = new ArrayList<Host>();
if (type == Host.Type.Storage) {
return null;
return suitableHosts;
}
String hostTag = offering.getHostTag();
if(hostTag != null){
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag);
}else{
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
}
// list all computing hosts, regardless of whether they support routing...it's random after all
List<? extends Host> hosts = _hostDao.listBy(type, clusterId, pod.getId(), dc.getId());
if (hosts.size() == 0) {
return null;
List<? extends Host> hosts = new ArrayList<HostVO>();
if(hostTag != null){
hosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag);
}else{
hosts = _hostDao.listBy(type, clusterId, podId, dcId);
}
s_logger.debug("Random Allocator found " + hosts.size() + " hosts");
if (hosts.size() == 0) {
return suitableHosts;
}
Collections.shuffle(hosts);
for (Host host : hosts) {
if (!avoid.contains(host)) {
return host;
if(suitableHosts.size() == returnUpTo){
break;
}
if (!avoid.shouldAvoid(host)) {
suitableHosts.add(host);
}else{
if (s_logger.isDebugEnabled()) {
s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() +" is in avoid set, skipping this and trying other available hosts");
}
}
}
return null;
if (s_logger.isDebugEnabled()) {
s_logger.debug("Random Host Allocator returning "+suitableHosts.size() +" suitable hosts");
}
return suitableHosts;
}
@Override

View File

@ -17,6 +17,7 @@
*/
package com.cloud.agent.manager.allocator.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -31,15 +32,19 @@ import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.DataCenter;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.PodCluster;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.VMTemplateVO;
import com.cloud.host.Host.Type;
import com.cloud.host.dao.HostDao;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.StoragePoolDao;
import com.cloud.storage.dao.VolumeDao;
@ -57,22 +62,26 @@ public class RecreateHostAllocator extends FirstFitRoutingAllocator {
@Inject ClusterDao _clusterDao;
@Inject AgentManager _agentMgr;
@Inject VolumeDao _volsDao;
@Inject DataCenterDao _dcDao;
@Inject HostDao _hostDao;
@Override
public Host allocateTo(VirtualMachineProfile<? extends VirtualMachine> vm, ServiceOffering offering, Host.Type type, DataCenterVO dc, HostPodVO pod,
Long clusterId, VMTemplateVO template, Set<Host> avoid) {
Host host = super.allocateTo(vm, offering, type, dc, pod, clusterId, template, avoid);
if (host != null) {
return host;
public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vm,DeploymentPlan plan, Type type,
ExcludeList avoid, int returnUpTo) {
List<Host> hosts = super.allocateTo(vm, plan, type, avoid, returnUpTo);
if (hosts != null && !hosts.isEmpty()) {
return hosts;
}
s_logger.debug("First fit was unable to find a host");
VirtualMachine.Type vmType = vm.getType();
if (vmType == VirtualMachine.Type.User) {
s_logger.debug("vm is not a system vm so let's just return null");
return null;
s_logger.debug("vm is not a system vm so let's just return empty list");
return new ArrayList<Host>();
}
DataCenter dc = _dcDao.findById(plan.getDataCenterId());
List<PodCluster> pcs = _agentMgr.listByDataCenter(dc.getId());
//getting rid of direct.attached.untagged.vlan.enabled config param: Bug 7204
//basic network type for zone maps to direct untagged case
@ -91,8 +100,14 @@ public class RecreateHostAllocator extends FirstFitRoutingAllocator {
}
}
Set<Pair<Long, Long>> avoidPcs = new HashSet<Pair<Long, Long>>();
for (Host h : avoid) {
avoidPcs.add(new Pair<Long, Long>(h.getPodId(), h.getClusterId()));
Set<Long> hostIdsToAvoid = avoid.getHostsToAvoid();
if(hostIdsToAvoid != null){
for (Long hostId : hostIdsToAvoid) {
Host h = _hostDao.findById(hostId);
if(h != null){
avoidPcs.add(new Pair<Long, Long>(h.getPodId(), h.getClusterId()));
}
}
}
for (Pair<Long, Long> pcId : avoidPcs) {
@ -101,16 +116,17 @@ public class RecreateHostAllocator extends FirstFitRoutingAllocator {
}
for (PodCluster p : pcs) {
clusterId = p.getCluster() == null ? null : p.getCluster().getId();
host = super.allocateTo(vm, offering, type, dc, p.getPod(),
clusterId, template, avoid);
if (host != null) {
return host;
long clusterId = p.getCluster() == null ? null : p.getCluster().getId();
DataCenterDeployment newPlan = new DataCenterDeployment(plan.getDataCenterId(), p.getPod().getId(), clusterId, null);
hosts = super.allocateTo(vm, newPlan, type, avoid, returnUpTo);
if (hosts != null && !hosts.isEmpty()) {
return hosts;
}
}
s_logger.debug("Unable to find any available pods at all!");
return null;
return new ArrayList<Host>();
}
@Override

View File

@ -17,18 +17,19 @@
*/
package com.cloud.agent.manager.allocator.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.host.dao.HostDao;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.VMTemplateVO;
import com.cloud.uservm.UserVm;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.vm.VirtualMachine;
@ -47,14 +48,19 @@ public class TestingAllocator implements HostAllocator {
String _name;
@Override
public Host allocateTo(VirtualMachineProfile<? extends VirtualMachine> vm, ServiceOffering offering, Host.Type type, DataCenterVO dc, HostPodVO pod,
Long clusterId, VMTemplateVO template, Set<Host> avoid) {
public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
ExcludeList avoid, int returnUpTo) {
List<Host> availableHosts = new ArrayList<Host>();
Host host = null;
if (type == Host.Type.Routing && _routingHost != null) {
return _hostDao.findById(_routingHost);
host = _hostDao.findById(_routingHost);
} else if (type == Host.Type.Storage && _storageHost != null) {
return _hostDao.findById(_storageHost);
host = _hostDao.findById(_storageHost);
}
return null;
if(host != null){
availableHosts.add(host);
}
return availableHosts;
}
@Override

View File

@ -283,7 +283,7 @@ public class AlertManagerImpl implements AlertManager {
int totalPublicIPs = _publicIPAddressDao.countIPsForDashboard(dcId, false);
int allocatedPublicIPs = _publicIPAddressDao.countIPsForDashboard(dcId, true);
CapacityVO newPublicIPCapacity = new CapacityVO(null, dcId, null, allocatedPublicIPs, totalPublicIPs, CapacityVO.CAPACITY_TYPE_PUBLIC_IP);
CapacityVO newPublicIPCapacity = new CapacityVO(null, dcId, null, null, allocatedPublicIPs, totalPublicIPs, CapacityVO.CAPACITY_TYPE_PUBLIC_IP);
newCapacities.add(newPublicIPCapacity);
}
@ -296,7 +296,7 @@ public class AlertManagerImpl implements AlertManager {
int totalPrivateIPs = _privateIPAddressDao.countIPs(podId, dcId, false);
int allocatedPrivateIPs = _privateIPAddressDao.countIPs(podId, dcId, true);
CapacityVO newPrivateIPCapacity = new CapacityVO(null, dcId, podId, allocatedPrivateIPs, totalPrivateIPs, CapacityVO.CAPACITY_TYPE_PRIVATE_IP);
CapacityVO newPrivateIPCapacity = new CapacityVO(null, dcId, podId, null, allocatedPrivateIPs, totalPrivateIPs, CapacityVO.CAPACITY_TYPE_PRIVATE_IP);
newCapacities.add(newPrivateIPCapacity);
}

View File

@ -347,6 +347,11 @@ public class ApiDBUtils {
return null;
}
}
public static String getHostTags(long hostId) {
return _agentMgr.getHostTags(hostId);
}
public static LoadBalancerVO findLoadBalancerById(Long loadBalancerId) {
return _loadBalancerDao.findById(loadBalancerId);

View File

@ -414,6 +414,7 @@ public class ApiResponseHelper implements ResponseGenerator {
offeringResponse.setDomain(ApiDBUtils.findDomainById(offering.getDomainId()).getName());
offeringResponse.setDomainId(offering.getDomainId());
}
offeringResponse.setHostTag(offering.getHostTag());
offeringResponse.setObjectName("serviceoffering");
return offeringResponse;
@ -538,6 +539,7 @@ public class ApiResponseHelper implements ResponseGenerator {
Long mem = ApiDBUtils.getMemoryUsagebyHost(host.getId());
hostResponse.setMemoryAllocated(mem);
hostResponse.setMemoryUsed(mem);
hostResponse.setHostTags(ApiDBUtils.getHostTags(host.getId()));
} else if (host.getType().toString().equals("Storage")) {
hostResponse.setDiskSizeTotal(host.getTotalSize());
hostResponse.setDiskSizeAllocated(0L);

View File

@ -11,5 +11,7 @@ import com.cloud.vm.VirtualMachine;
public interface CapacityManager extends Manager {
public boolean releaseVmCapacity(VirtualMachine vm, boolean moveFromReserved, boolean moveToReservered, Long hostId);
boolean allocateVmCapacity(long hostId, Integer cpu, long ram, boolean fromLastHost);
boolean allocateVmCapacity(VirtualMachine vm, boolean fromLastHost);
boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity);
}

View File

@ -174,10 +174,22 @@ public class CapacityManagerImpl implements CapacityManager , StateListener<Stat
@DB
@Override
public boolean allocateVmCapacity(long hostId, Integer cpu, long ram, boolean fromLastHost) {
public boolean allocateVmCapacity(VirtualMachine vm, boolean fromLastHost) {
long hostId = vm.getHostId();
ServiceOfferingVO svo = _offeringsDao.findById(vm.getServiceOfferingId());
CapacityVO capacityCpu = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_CPU);
CapacityVO capacityMem = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_MEMORY);
if (capacityCpu == null || capacityMem == null || svo == null) {
return false;
}
int cpu = svo.getCpu() * svo.getSpeed();
long ram = svo.getRamSize() * 1024L * 1024L;
Transaction txn = Transaction.currentTxn();
try {
@ -243,6 +255,90 @@ public class CapacityManagerImpl implements CapacityManager , StateListener<Stat
return false;
}
}
@Override
public boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean checkFromReservedCapacity){
boolean hasCapacity = false;
if (s_logger.isDebugEnabled()) {
s_logger.debug("Checking if host: " + hostId + " has enough capacity for requested CPU: "+ cpu + " and requested RAM: "+ ram);
}
CapacityVO capacityCpu = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_CPU);
CapacityVO capacityMem = _capacityDao.findByHostIdType(hostId, CapacityVO.CAPACITY_TYPE_MEMORY);
long usedCpu = capacityCpu.getUsedCapacity();
long usedMem = capacityMem.getUsedCapacity();
long reservedCpu = capacityCpu.getReservedCapacity();
long reservedMem = capacityMem.getReservedCapacity();
long totalCpu = capacityCpu.getTotalCapacity();
long totalMem = capacityMem.getTotalCapacity();
long freeCpu = totalCpu - (reservedCpu + usedCpu);
long freeMem = totalMem - (reservedMem + usedMem);
String failureReason = "";
if (checkFromReservedCapacity) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Checking from reserved capacity of the host, looks like allocating to last host");
}
/*alloc from reserved*/
if (reservedCpu >= cpu){
if(reservedMem >= ram) {
hasCapacity = true;
}else{
failureReason = "Host does not have enough reserved RAM available";
}
}else{
failureReason = "Host does not have enough reserved CPU available";
}
} else {
/*alloc from free resource*/
if ((reservedCpu + usedCpu + cpu <= totalCpu)) {
if((reservedMem + usedMem + ram <= totalMem)){
hasCapacity = true;
}else{
failureReason = "Host does not have enough RAM available";
}
}else{
failureReason = "Host does not have enough CPU available";
}
}
if (hasCapacity) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Host has enough CPU and RAM available");
}
s_logger.debug("STATS: Can alloc CPU from host: " + hostId + ", used: " + usedCpu + ", reserved: " +
reservedCpu + ", total: " + totalCpu +
"; requested cpu:" + cpu + ",alloc_from_last_host?:" + checkFromReservedCapacity);
s_logger.debug("STATS: Can alloc MEM from host: " + hostId + ", used: " + usedMem + ", reserved: " +
reservedMem + ", total: " + totalMem + "; requested mem: " + ram + ",alloc_from_last_host?:" + checkFromReservedCapacity);
} else {
if (checkFromReservedCapacity) {
s_logger.debug("STATS: Failed to alloc resource from host: " + hostId + " reservedCpu: " + reservedCpu + ", requested cpu: " + cpu +
", reservedMem: " + reservedMem + ", requested mem: " + ram);
} else {
s_logger.debug("STATS: Failed to alloc resource from host: " + hostId + " reservedCpu: " + reservedCpu + ", used cpu: " + usedCpu + ", requested cpu: " + cpu +
", total cpu: " + totalCpu +
", reservedMem: " + reservedMem + ", used Mem: " + usedMem + ", requested mem: " + ram + ", total Mem:" + totalMem);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Free CPU: "+freeCpu + " , Requested CPU: "+cpu);
s_logger.debug("Free RAM: "+freeMem + " , Requested RAM: "+ram);
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(failureReason + ", cannot allocate to this host.");
}
}
return hasCapacity;
}
public class HostCapacityCollector implements Runnable {
@ -383,6 +479,16 @@ public class CapacityManagerImpl implements CapacityManager , StateListener<Stat
}
}
if((newState == State.Starting || newState == State.Migrating) && vm.getHostId() != null){
boolean fromLastHost = false;
if(vm.getLastHostId() == vm.getHostId()){
s_logger.debug("VM starting again on the last host it was stopped on");
fromLastHost = true;
}
allocateVmCapacity(vm,fromLastHost);
}
return true;
}

View File

@ -29,5 +29,5 @@ public interface CapacityDao extends GenericDao<CapacityVO, Long> {
CapacityVO findByHostIdType(Long hostId, short capacityType);
void clearNonStorageCapacities2();
List<CapacityVO> findByHostorPoolId(Long hostorPoolId);
List<Long> orderClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone);
}

View File

@ -19,6 +19,10 @@
package com.cloud.capacity.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Local;
@ -29,6 +33,7 @@ import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
@Local(value = { CapacityDao.class })
public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements CapacityDao {
@ -39,6 +44,13 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
private static final String CLEAR_STORAGE_CAPACITIES = "DELETE FROM `cloud`.`op_host_capacity` WHERE capacity_type=2 OR capacity_type=3 OR capacity_type=6"; //clear storage and secondary_storage capacities
private static final String CLEAR_NON_STORAGE_CAPACITIES = "DELETE FROM `cloud`.`op_host_capacity` WHERE capacity_type<>2 AND capacity_type<>3 AND capacity_type<>6"; //clear non-storage and non-secondary_storage capacities
private static final String CLEAR_NON_STORAGE_CAPACITIES2 = "DELETE FROM `cloud`.`op_host_capacity` WHERE capacity_type<>2 AND capacity_type<>3 AND capacity_type<>6 AND capacity_type<>0 AND capacity_type<>1"; //clear non-storage and non-secondary_storage capacities
private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART1 = "SELECT DISTINCT cluster_id FROM `cloud`.`op_host_capacity` WHERE ";
private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART2 = " AND capacity_type = ? AND (total_capacity - used_capacity + reserved_capacity) >= ? " +
"AND cluster_id IN (SELECT distinct cluster_id FROM `cloud`.`op_host_capacity` WHERE ";
private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3 = " AND capacity_type = ? AND (total_capacity - used_capacity + reserved_capacity) >= ?) " +
"ORDER BY (total_capacity - used_capacity + reserved_capacity) DESC";
private SearchBuilder<CapacityVO> _hostIdTypeSearch;
private SearchBuilder<CapacityVO> _hostOrPoolIdSearch;
@ -138,5 +150,55 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
SearchCriteria<CapacityVO> sc = _hostOrPoolIdSearch.create();
sc.setParameters("hostId", hostorPoolId);
return listBy(sc);
}
}
@Override
public List<Long> orderClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone){
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
List<Long> result = new ArrayList<Long>();
StringBuilder sql = new StringBuilder(LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART1);
if(isZone){
sql.append("data_center_id = ?");
}else{
sql.append("pod_id = ?");
}
sql.append(LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART2);
if(isZone){
sql.append("data_center_id = ?");
}else{
sql.append("pod_id = ?");
}
sql.append(LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3);
try {
pstmt = txn.prepareAutoCloseStatement(sql.toString());
pstmt.setLong(1, id);
if(capacityTypeForOrdering == CapacityVO.CAPACITY_TYPE_CPU){
pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_CPU);
pstmt.setLong(3, requiredCpu);
pstmt.setLong(4, id);
pstmt.setShort(5, CapacityVO.CAPACITY_TYPE_MEMORY);
pstmt.setLong(6, requiredRam);
}else{
pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_MEMORY);
pstmt.setLong(3, requiredRam);
pstmt.setLong(4, id);
pstmt.setShort(5, CapacityVO.CAPACITY_TYPE_CPU);
pstmt.setLong(6, requiredCpu);
}
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result.add(rs.getLong(1));
}
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + sql, e);
} catch (Throwable e) {
throw new CloudRuntimeException("Caught: " + sql, e);
}
}
}

View File

@ -165,7 +165,9 @@ public enum Config {
ControlCidr("Advanced", ManagementServer.class, String.class, "control.cidr", "169.254.0.0/16", "Changes the cidr for the control network traffic. Defaults to using link local. Must be unique within pods", null),
ControlGateway("Advanced", ManagementServer.class, String.class, "control.gateway", "169.254.0.1", "gateway for the control network traffic", null),
UseUserConcentratedPodAllocation("Advanced", ManagementServer.class, Boolean.class, "use.user.concentrated.pod.allocation", "true", "If true, deployment planner applies the user concentration heuristic during VM resource allocation", "true,false"),
HostCapacityTypeToOrderClusters("Advanced", ManagementServer.class, String.class, "host.capacityType.to.order.clusters", "CPU", "The host capacity type is used by deployment planner to order clusters during VM resource allocation", "CPU,RAM"),
// XenServer
VmAllocationAlgorithm("Advanced", ManagementServer.class, String.class, "vm.allocation.algorithm", "random", "If 'random', hosts within a pod will be randomly considered for VM/volume allocation. If 'firstfit', they will be considered on a first-fit basis.", null),
XenPublicNetwork("Network", ManagementServer.class, String.class, "xen.public.network.device", null, "[ONLY IF THE PUBLIC NETWORK IS ON A DEDICATED NIC]:The network name label of the physical device dedicated to the public network on a XenServer host", null),

View File

@ -68,9 +68,10 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
* @param offerHA
* @param useVirtualNetwork
* @param domainId
* @param hostTag
* @return ID
*/
ServiceOfferingVO createServiceOffering(long userId, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, String tags, Long domainId);
ServiceOfferingVO createServiceOffering(long userId, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, String tags, Long domainId, String hostTag);
/**
* Creates a new disk offering

View File

@ -1303,17 +1303,17 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
}
return createServiceOffering(userId, cmd.getServiceOfferingName(), cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(),
localStorageRequired, offerHA, cmd.getTags(),cmd.getDomainId());
localStorageRequired, offerHA, cmd.getTags(),cmd.getDomainId(), cmd.getHostTag());
}
@Override
public ServiceOfferingVO createServiceOffering(long userId, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, String tags, Long domainId) {
public ServiceOfferingVO createServiceOffering(long userId, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA, String tags, Long domainId, String hostTag) {
String networkRateStr = _configDao.getValue("network.throttling.rate");
String multicastRateStr = _configDao.getValue("multicast.throttling.rate");
int networkRate = ((networkRateStr == null) ? 200 : Integer.parseInt(networkRateStr));
int multicastRate = ((multicastRateStr == null) ? 10 : Integer.parseInt(multicastRateStr));
tags = cleanupTags(tags);
ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, multicastRate, offerHA, displayText, localStorageRequired, false, tags, false,domainId);
ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, multicastRate, offerHA, displayText, localStorageRequired, false, tags, false,domainId, hostTag);
if ((offering = _serviceOfferingDao.persist(offering)) != null) {
return offering;

View File

@ -18,6 +18,7 @@
package com.cloud.dc.dao;
import java.util.List;
import java.util.Map;
import com.cloud.dc.ClusterVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
@ -30,4 +31,5 @@ public interface ClusterDao extends GenericDao<ClusterVO, Long> {
List<ClusterVO> listByZoneId(long zoneId);
List<HypervisorType> getAvailableHypervisorInZone(long zoneId);
List<ClusterVO> listByDcHyType(long dcId, String hyType);
Map<Long, List<Long>> getPodClusterIdMap(List<Long> clusterIds);
}

View File

@ -17,16 +17,24 @@
*/
package com.cloud.dc.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import com.cloud.capacity.CapacityVO;
import com.cloud.dc.ClusterVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
@Local(value=ClusterDao.class)
public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements ClusterDao {
@ -36,6 +44,10 @@ public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements C
protected final SearchBuilder<ClusterVO> AvailHyperSearch;
protected final SearchBuilder<ClusterVO> ZoneSearch;
protected final SearchBuilder<ClusterVO> ZoneHyTypeSearch;
private static final String GET_POD_CLUSTER_MAP_PREFIX = "SELECT pod_id, id FROM cloud.cluster WHERE cluster.id IN( ";
private static final String GET_POD_CLUSTER_MAP_SUFFIX = " )";
protected ClusterDaoImpl() {
super();
@ -116,4 +128,43 @@ public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements C
return hypers;
}
@Override
public Map<Long, List<Long>> getPodClusterIdMap(List<Long> clusterIds){
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
Map<Long, List<Long>> result = new HashMap<Long, List<Long>>();
try {
StringBuilder sql = new StringBuilder(GET_POD_CLUSTER_MAP_PREFIX);
if (clusterIds.size() > 0) {
for (Long clusterId : clusterIds) {
sql.append(clusterId).append(",");
}
sql.delete(sql.length()-1, sql.length());
sql.append(GET_POD_CLUSTER_MAP_SUFFIX);
}
pstmt = txn.prepareAutoCloseStatement(sql.toString());
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Long podId = rs.getLong(1);
Long clusterIdInPod = rs.getLong(2);
if(result.containsKey(podId)){
List<Long> clusterList = result.get(podId);
clusterList.add(clusterIdInPod);
result.put(podId, clusterList);
}else{
List<Long> clusterList = new ArrayList<Long>();
clusterList.add(clusterIdInPod);
result.put(podId, clusterList);
}
}
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + GET_POD_CLUSTER_MAP_PREFIX, e);
} catch (Throwable e) {
throw new CloudRuntimeException("Caught: " + GET_POD_CLUSTER_MAP_PREFIX, e);
}
}
}

View File

@ -2,12 +2,16 @@ package com.cloud.deploy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.capacity.CapacityManager;
import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDao;
@ -21,7 +25,6 @@ import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
@ -29,30 +32,54 @@ import com.cloud.host.dao.DetailsDao;
import com.cloud.host.dao.HostDao;
import com.cloud.offering.ServiceOffering;
import com.cloud.org.Cluster;
import com.cloud.storage.GuestOSCategoryVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.allocator.StoragePoolAllocator;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.storage.dao.StoragePoolDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Adapters;
import com.cloud.utils.component.Inject;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
@Local(value=DeploymentPlanner.class)
public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner {
private static final Logger s_logger = Logger.getLogger(FirstFitPlanner.class);
@Inject private HostDao _hostDao;
@Inject private CapacityDao _capacityDao;
@Inject private DataCenterDao _dcDao;
@Inject private HostPodDao _podDao;
@Inject private ClusterDao _clusterDao;
@Inject DetailsDao _hostDetailsDao = null;
@Inject GuestOSDao _guestOSDao = null;
@Inject GuestOSCategoryDao _guestOSCategoryDao = null;
@Inject private DiskOfferingDao _diskOfferingDao;
@Inject private StoragePoolHostDao _poolHostDao;
@Inject private UserVmDao _vmDao;
@Inject VMInstanceDao _vmInstanceDao;
@Inject protected VolumeDao _volsDao;
@Inject CapacityManager _capacityMgr;
@Inject ConfigurationDao _configDao;
@Inject protected StoragePoolDao _storagePoolDao;
@Inject CapacityDao _capacityDao;
@Inject(adapter=StoragePoolAllocator.class)
protected Adapters<StoragePoolAllocator> _storagePoolAllocators;
@Inject(adapter=HostAllocator.class)
protected Adapters<HostAllocator> _hostAllocators;
private static int RETURN_UPTO_ALL = -1;
@Override
public DeployDestination plan(VirtualMachineProfile vmProfile,
@ -65,104 +92,365 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner {
int cpu_requested = offering.getCpu() * offering.getSpeed();
long ram_requested = offering.getRamSize() * 1024L * 1024L;
s_logger.debug("try to allocate a host from dc:" + plan.getDataCenterId() + ", pod:" + plan.getPodId() + ",cluster:" + plan.getClusterId() +
s_logger.debug("In FirstFitPlanner:: plan");
s_logger.debug("Trying to allocate a host and storage pools from dc:" + plan.getDataCenterId() + ", pod:" + plan.getPodId() + ",cluster:" + plan.getClusterId() +
", requested cpu: " + cpu_requested + ", requested ram: " + ram_requested);
s_logger.debug("Is ROOT volume READY (pool already allocated)?: " + (plan.getPoolId()!=null ? "Yes": "No"));
if (vm.getLastHostId() != null) {
s_logger.debug("This VM has last host_id specified, trying to choose the same host: " +vm.getLastHostId());
HostVO host = _hostDao.findById(vm.getLastHostId());
if (host != null && host.getStatus() == Status.Up) {
boolean canDepployToLastHost = deployToHost(host, cpu_requested, ram_requested, true, avoid);
if (canDepployToLastHost) {
Pod pod = _podDao.findById(vm.getPodId());
Cluster cluster = _clusterDao.findById(host.getClusterId());
return new DeployDestination(dc, pod, cluster, host);
if(host == null){
s_logger.debug("The last host of this VM cannot be found");
}else{
if (host.getStatus() == Status.Up) {
if(_capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, true)){
s_logger.debug("The last host of this VM is UP and has enough capacity");
s_logger.debug("Now checking for suitable pools under zone: "+vm.getDataCenterId() +", pod: "+ vm.getPodId()+", cluster: "+ host.getClusterId());
//search for storage under the zone, pod, cluster of the last host.
DataCenterDeployment lastPlan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodId(), host.getClusterId(), null);
Map<Volume, List<StoragePool>> suitableVolumeStoragePools = findSuitablePoolsForVolumes(vmProfile, lastPlan, avoid, RETURN_UPTO_ALL);
//choose the potential pool for this VM for this host
if(!suitableVolumeStoragePools.isEmpty()){
List<Host> suitableHosts = new ArrayList<Host>();
suitableHosts.add(host);
Pair<Host, Map<Volume, StoragePool>> potentialResources = findPotentialDeploymentResources(suitableHosts, suitableVolumeStoragePools);
if(potentialResources != null){
Pod pod = _podDao.findById(vm.getPodId());
Cluster cluster = _clusterDao.findById(host.getClusterId());
DeployDestination dest = new DeployDestination(dc, pod, cluster, host, potentialResources.second());
s_logger.debug("Returning Deployment Destination: "+ dest);
return dest;
}
}
}else{
s_logger.debug("The last host of this VM does not have enough capacity");
}
}else{
s_logger.debug("The last host of this VM is not UP, host status is: "+host.getStatus().name());
}
}
s_logger.debug("Cannot choose the last host to deploy this VM ");
}
/*Go through all the pods/clusters under zone*/
List<HostPodVO> pods = null;
if (plan.getPodId() != null) {
HostPodVO pod = _podDao.findById(plan.getPodId());
if (pod != null && dc.getId() == pod.getDataCenterId()) {
pods = new ArrayList<HostPodVO>(1);
pods.add(pod);
} else {
s_logger.debug("Can't enforce the pod selector");
List<Long> clusterList = new ArrayList<Long>();
if (plan.getClusterId() != null) {
Long clusterIdSpecified = plan.getClusterId();
s_logger.debug("Searching resources only under specified Cluster: "+ clusterIdSpecified);
ClusterVO cluster = _clusterDao.findById(plan.getClusterId());
if (cluster != null ){
clusterList.add(clusterIdSpecified);
return checkClustersforDestination(clusterList, vmProfile, plan, avoid, dc, _allocationAlgorithm);
}else{
s_logger.debug("The specified cluster cannot be found, returning.");
avoid.addPod(plan.getClusterId());
return null;
}
}
if (pods == null)
pods = _podDao.listByDataCenterId(plan.getDataCenterId());
if (_allocationAlgorithm != null && _allocationAlgorithm.equalsIgnoreCase("random")) {
Collections.shuffle(pods);
}else if (plan.getPodId() != null) {
//consider clusters under this pod only
Long podIdSpecified = plan.getPodId();
s_logger.debug("Searching resources only under specified Pod: "+ podIdSpecified);
HostPodVO pod = _podDao.findById(podIdSpecified);
if (pod != null) {
//list clusters under this pod by cpu and ram capacity
clusterList = listClustersByCapacity(podIdSpecified, cpu_requested, ram_requested, avoid, false);
if(!clusterList.isEmpty()){
if(avoid.getClustersToAvoid() != null){
if (s_logger.isDebugEnabled()) {
s_logger.debug("Removing from the clusterId list these clusters from avoid set: "+ avoid.getClustersToAvoid());
}
clusterList.removeAll(avoid.getClustersToAvoid());
}
DeployDestination dest = checkClustersforDestination(clusterList, vmProfile, plan, avoid, dc, _allocationAlgorithm);
if(dest == null){
avoid.addPod(plan.getPodId());
}
return dest;
}else{
if (s_logger.isDebugEnabled()) {
s_logger.debug("No clusters found under this pod, having a host with enough capacity, returning.");
}
avoid.addPod(plan.getPodId());
return null;
}
} else {
s_logger.debug("The specified Pod cannot be found, returning.");
avoid.addPod(plan.getPodId());
return null;
}
}else{
//consider all clusters under this zone.
s_logger.debug("Searching all possible resources under this Zone: "+ plan.getDataCenterId());
//list clusters under this zone by cpu and ram capacity
List<Long> prioritizedClusterIds = listClustersByCapacity(plan.getDataCenterId(), cpu_requested, ram_requested, avoid, true);
if(!prioritizedClusterIds.isEmpty()){
if(avoid.getClustersToAvoid() != null){
if (s_logger.isDebugEnabled()) {
s_logger.debug("Removing from the clusterId list these clusters from avoid set: "+ avoid.getClustersToAvoid());
}
prioritizedClusterIds.removeAll(avoid.getClustersToAvoid());
}
boolean applyUserConcentrationPodHeuristic = Boolean.parseBoolean(_configDao.getValue(Config.UseUserConcentratedPodAllocation.key()));
if(applyUserConcentrationPodHeuristic && vmProfile.getOwner() != null){
//user has VMs in certain pods. - prioritize those pods first
//UserConcentratedPod strategy
long accountId = vmProfile.getOwner().getAccountId();
List<Long> podIds = listPodsByUserConcentration(plan.getDataCenterId(), accountId);
if(!podIds.isEmpty()){
if(avoid.getPodsToAvoid() != null){
if (s_logger.isDebugEnabled()) {
s_logger.debug("Removing from the pod list these pods from avoid set: "+ avoid.getPodsToAvoid());
}
podIds.removeAll(avoid.getPodsToAvoid());
}
clusterList = reorderClustersByPods(prioritizedClusterIds, podIds);
}else{
clusterList = prioritizedClusterIds;
}
}else{
clusterList = prioritizedClusterIds;
}
return checkClustersforDestination(clusterList, vmProfile, plan, avoid, dc, _allocationAlgorithm);
}else{
if (s_logger.isDebugEnabled()) {
s_logger.debug("No clusters found having a host with enough capacity, returning.");
}
return null;
}
}
}
private DeployDestination checkClustersforDestination(List<Long> clusterList, VirtualMachineProfile vmProfile,
DeploymentPlan plan, ExcludeList avoid, DataCenter dc, String _allocationAlgorithm){
for (HostPodVO hostPod : pods) {
if (avoid.shouldAvoid(hostPod)) {
for(Long clusterId : clusterList){
Cluster clusterVO = _clusterDao.findById(clusterId);
if (clusterVO.getHypervisorType() != vmProfile.getHypervisorType()) {
s_logger.debug("Cluster: "+clusterId + " has HyperVisorType that does not match the VM, skipping this cluster");
avoid.addCluster(clusterVO.getId());
continue;
}
List<ClusterVO> clusters = null;
if (plan.getClusterId() != null) {
ClusterVO cluster = _clusterDao.findById(plan.getClusterId());
if (cluster != null && hostPod.getId() == cluster.getPodId()) {
clusters = new ArrayList<ClusterVO>(1);
clusters.add(cluster);
} else {
s_logger.debug("Can't enforce the cluster selector");
return null;
}
}
if (clusters == null) {
clusters = _clusterDao.listByPodId(hostPod.getId());
}
if (_allocationAlgorithm != null && _allocationAlgorithm.equalsIgnoreCase("random")) {
Collections.shuffle(clusters);
}
for (ClusterVO clusterVO : clusters) {
if (avoid.shouldAvoid(clusterVO)) {
continue;
}
if (clusterVO.getHypervisorType() != vmProfile.getHypervisorType()) {
avoid.addCluster(clusterVO.getId());
continue;
}
List<HostVO> hosts = _hostDao.listBy(Host.Type.Routing, clusterVO.getId(), hostPod.getId(), dc.getId());
s_logger.debug("Checking resources in Cluster: "+clusterId + " under Pod: "+clusterVO.getPodId());
//search for resources(hosts and storage) under this zone, pod, cluster.
DataCenterDeployment potentialPlan = new DataCenterDeployment(plan.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), plan.getPoolId());
//find suitable hosts under this cluster, need as many hosts as we get.
List<Host> suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, RETURN_UPTO_ALL);
//if found suitable hosts in this cluster, find suitable storage pools for each volume of the VM
if(suitableHosts != null && !suitableHosts.isEmpty()){
if (_allocationAlgorithm != null && _allocationAlgorithm.equalsIgnoreCase("random")) {
Collections.shuffle(hosts);
Collections.shuffle(suitableHosts);
}
// We will try to reorder the host lists such that we give priority to hosts that have
// the minimums to support a VM's requirements
hosts = prioritizeHosts(vmProfile.getTemplate(), hosts);
for (HostVO hostVO : hosts) {
boolean canDeployToHost = deployToHost(hostVO, cpu_requested, ram_requested, false, avoid);
if (canDeployToHost) {
Pod pod = _podDao.findById(hostPod.getId());
Cluster cluster = _clusterDao.findById(clusterVO.getId());
Host host = _hostDao.findById(hostVO.getId());
return new DeployDestination(dc, pod, cluster, host);
Map<Volume, List<StoragePool>> suitableVolumeStoragePools = findSuitablePoolsForVolumes(vmProfile, potentialPlan, avoid, RETURN_UPTO_ALL);
//choose the potential host and pool for the VM
if(!suitableVolumeStoragePools.isEmpty()){
Pair<Host, Map<Volume, StoragePool>> potentialResources = findPotentialDeploymentResources(suitableHosts, suitableVolumeStoragePools);
if(potentialResources != null){
Pod pod = _podDao.findById(clusterVO.getPodId());
Host host = _hostDao.findById(potentialResources.first().getId());
DeployDestination dest = new DeployDestination(dc, pod, clusterVO, host, potentialResources.second() );
s_logger.debug("Returning Deployment Destination: "+ dest);
return dest;
}
avoid.addHost(hostVO.getId());
}else{
s_logger.debug("No suitable storagePools found under this Cluster: "+clusterId);
}
avoid.addCluster(clusterVO.getId());
}else{
s_logger.debug("No suitable hosts found under this Cluster: "+clusterId);
}
avoid.addPod(hostPod.getId());
avoid.addCluster(clusterVO.getId());
}
s_logger.debug("Could not find suitable Deployment Destination for this VM under any clusters, returning. ");
return null;
}
private List<Long> reorderClustersByPods(List<Long> clusterIds, List<Long> podIds) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Reordering cluster list as per pods ordered by user concentration");
}
Map<Long, List<Long>> podClusterMap = _clusterDao.getPodClusterIdMap(clusterIds);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Pod To cluster Map is: "+podClusterMap );
}
List<Long> reorderedClusters = new ArrayList<Long>();
for (Long pod : podIds){
if(podClusterMap.containsKey(pod)){
List<Long> clustersOfThisPod = (List<Long>)podClusterMap.get(pod);
if(clustersOfThisPod != null){
reorderedClusters.addAll(clustersOfThisPod);
clusterIds.removeAll(clustersOfThisPod);
}
}
}
reorderedClusters.addAll(clusterIds);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Reordered cluster list: "+reorderedClusters );
}
return reorderedClusters;
}
protected List<Long> listPodsByUserConcentration(long zoneId, long accountId){
if (s_logger.isDebugEnabled()) {
s_logger.debug("Applying UserConcentratedPod heuristic for account: "+ accountId);
}
List<Long> prioritizedPods = _vmDao.listPodIdsHavingVmsforAccount(zoneId, accountId);
if (s_logger.isDebugEnabled()) {
s_logger.debug("List of pods to be considered, after applying UserConcentratedPod heuristic: "+ prioritizedPods);
}
return prioritizedPods;
}
protected List<Long> listClustersByCapacity(long id, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone){
//look at the aggregate available cpu and ram per cluster
//although an aggregate value may be false indicator that a cluster can host a vm, it will at the least eliminate those clusters which definitely cannot
//we need clusters having enough cpu AND RAM
if (s_logger.isDebugEnabled()) {
s_logger.debug("Listing clusters that have enough aggregate CPU and RAM capacity under this "+(isZone ? "Zone: " : "Pod: " )+id);
}
String capacityTypeToOrder = _configDao.getValue(Config.HostCapacityTypeToOrderClusters.key());
short capacityType = CapacityVO.CAPACITY_TYPE_CPU;
if("RAM".equalsIgnoreCase(capacityTypeToOrder)){
capacityType = CapacityVO.CAPACITY_TYPE_MEMORY;
}
List<Long> clusterIdswithEnoughCapacity = _capacityDao.orderClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone);
if (s_logger.isDebugEnabled()) {
s_logger.debug("ClusterId List having enough aggregate capacity: "+clusterIdswithEnoughCapacity );
}
return clusterIdswithEnoughCapacity;
}
protected Pair<Host, Map<Volume, StoragePool>> findPotentialDeploymentResources(List<Host> suitableHosts, Map<Volume, List<StoragePool>> suitableVolumeStoragePools){
s_logger.debug("Trying to find a potenial host and associated storage pools from the suitable host/pool lists for this VM");
boolean hostCanAccessPool = false;
Map<Volume, StoragePool> storage = new HashMap<Volume, StoragePool>();
for(Host potentialHost : suitableHosts){
for(Volume vol : suitableVolumeStoragePools.keySet()){
s_logger.debug("Checking if host: "+potentialHost.getId() +" can access any suitable storage pool for volume: "+ vol.getVolumeType());
List<StoragePool> volumePoolList = suitableVolumeStoragePools.get(vol);
hostCanAccessPool = false;
for(StoragePool potentialSPool : volumePoolList){
if(hostCanAccessSPool(potentialHost, potentialSPool)){
storage.put(vol, potentialSPool);
hostCanAccessPool = true;
break;
}
}
if(!hostCanAccessPool){
break;
}
}
if(hostCanAccessPool){
s_logger.debug("Found a potential host and associated storage pools for this VM");
return new Pair<Host, Map<Volume, StoragePool>>(potentialHost, storage);
}
}
s_logger.debug("Could not find a potential host that has associated storage pools from the suitable host/pool lists for this VM");
return null;
}
protected boolean hostCanAccessSPool(Host host, StoragePool pool){
boolean hostCanAccessSPool = false;
StoragePoolHostVO hostPoolLinkage = _poolHostDao.findByPoolHost(pool.getId(), host.getId());
if(hostPoolLinkage != null){
hostCanAccessSPool = true;
}
s_logger.debug("Host: "+ host.getId() + (hostCanAccessSPool ?" can" : " cannot") + " access pool: "+ pool.getId());
return hostCanAccessSPool;
}
protected List<Host> findSuitableHosts(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo){
List<Host> suitableHosts = new ArrayList<Host>();
Enumeration<HostAllocator> enHost = _hostAllocators.enumeration();
s_logger.debug("Calling HostAllocators to find suitable hosts");
while (enHost.hasMoreElements()) {
final HostAllocator allocator = enHost.nextElement();
suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, avoid, returnUpTo);
if (suitableHosts != null && !suitableHosts.isEmpty()) {
break;
}
}
if(suitableHosts.isEmpty()){
s_logger.debug("No suitable hosts found");
}
return suitableHosts;
}
protected Map<Volume, List<StoragePool>> findSuitablePoolsForVolumes(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo){
List<VolumeVO> volumesTobeCreated = _volsDao.findUsableVolumesForInstance(vmProfile.getId());
Map<Volume, List<StoragePool>> suitableVolumeStoragePools = new HashMap<Volume, List<StoragePool>>();
s_logger.debug("Calling StoragePoolAllocators to find suitable pools");
//for each volume find list of suitable storage pools by calling the allocators
for (VolumeVO toBeCreated : volumesTobeCreated) {
s_logger.debug("Checking suitable pools for volume (Id, Type): ("+toBeCreated.getId() +"," +toBeCreated.getVolumeType().name() + ")");
//skip the volume if its already in READY state and has pool allocated
if(plan.getPoolId() != null){
if (toBeCreated.getPoolId() != null && toBeCreated.getPoolId().longValue() == plan.getPoolId().longValue()) {
s_logger.debug("Volume is in READY state and has pool already allocated.");
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
StoragePoolVO pool = _storagePoolDao.findById(toBeCreated.getPoolId());
suitablePools.add(pool);
suitableVolumeStoragePools.put(toBeCreated, suitablePools);
continue;
}
}
DiskOfferingVO diskOffering = _diskOfferingDao.findById(toBeCreated.getDiskOfferingId());
DiskProfile diskProfile = new DiskProfile(toBeCreated, diskOffering, vmProfile.getHypervisorType());
boolean foundPotentialPools = false;
Enumeration<StoragePoolAllocator> enPool = _storagePoolAllocators.enumeration();
while (enPool.hasMoreElements()) {
final StoragePoolAllocator allocator = enPool.nextElement();
final List<StoragePool> suitablePools = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid, returnUpTo);
if (suitablePools != null && !suitablePools.isEmpty()) {
suitableVolumeStoragePools.put(toBeCreated, suitablePools);
foundPotentialPools = true;
break;
}
}
if(!foundPotentialPools){
//No suitable storage pools found under this cluster for this volume.
break;
}
}
if(suitableVolumeStoragePools.isEmpty()){
s_logger.debug("No suitable pools found");
}
return suitableVolumeStoragePools;
}
@Override
@ -171,119 +459,4 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner {
// TODO Auto-generated method stub
return false;
}
@DB
protected boolean deployToHost(HostVO host, Integer cpu, long ram, boolean fromLastHost, ExcludeList avoid) {
if (avoid.shouldAvoid(host)) {
return false;
}
return _capacityMgr.allocateVmCapacity(host.getId(), cpu, ram, fromLastHost);
}
protected List<HostVO> prioritizeHosts(VirtualMachineTemplate template, List<HostVO> hosts) {
if (template == null) {
return hosts;
}
// Determine the guest OS category of the template
String templateGuestOSCategory = getTemplateGuestOSCategory(template);
List<HostVO> prioritizedHosts = new ArrayList<HostVO>();
// If a template requires HVM and a host doesn't support HVM, remove it from consideration
List<HostVO> hostsToCheck = new ArrayList<HostVO>();
if (template.isRequiresHvm()) {
for (HostVO host : hosts) {
if (hostSupportsHVM(host)) {
hostsToCheck.add(host);
}
}
} else {
hostsToCheck.addAll(hosts);
}
// If a host is tagged with the same guest OS category as the template, move it to a high priority list
// If a host is tagged with a different guest OS category than the template, move it to a low priority list
List<HostVO> highPriorityHosts = new ArrayList<HostVO>();
List<HostVO> lowPriorityHosts = new ArrayList<HostVO>();
for (HostVO host : hostsToCheck) {
String hostGuestOSCategory = getHostGuestOSCategory(host);
if (hostGuestOSCategory == null) {
continue;
} else if (templateGuestOSCategory.equals(hostGuestOSCategory)) {
highPriorityHosts.add(host);
} else {
lowPriorityHosts.add(host);
}
}
hostsToCheck.removeAll(highPriorityHosts);
hostsToCheck.removeAll(lowPriorityHosts);
// Prioritize the remaining hosts by HVM capability
for (HostVO host : hostsToCheck) {
if (!template.isRequiresHvm() && !hostSupportsHVM(host)) {
// Host and template both do not support hvm, put it as first consideration
prioritizedHosts.add(0, host);
} else {
// Template doesn't require hvm, but the machine supports it, make it last for consideration
prioritizedHosts.add(host);
}
}
// Merge the lists
prioritizedHosts.addAll(0, highPriorityHosts);
prioritizedHosts.addAll(lowPriorityHosts);
return prioritizedHosts;
}
protected boolean hostSupportsHVM(HostVO host) {
// Determine host capabilities
String caps = host.getCapabilities();
if (caps != null) {
String[] tokens = caps.split(",");
for (String token : tokens) {
if (token.contains("hvm")) {
return true;
}
}
}
return false;
}
protected String getHostGuestOSCategory(HostVO host) {
DetailVO hostDetail = _hostDetailsDao.findDetail(host.getId(), "guest.os.category.id");
if (hostDetail != null) {
String guestOSCategoryIdString = hostDetail.getValue();
long guestOSCategoryId;
try {
guestOSCategoryId = Long.parseLong(guestOSCategoryIdString);
} catch (Exception e) {
return null;
}
GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId);
if (guestOSCategory != null) {
return guestOSCategory.getName();
} else {
return null;
}
} else {
return null;
}
}
protected String getTemplateGuestOSCategory(VirtualMachineTemplate template) {
long guestOSId = template.getGuestOSId();
GuestOSVO guestOS = _guestOSDao.findById(guestOSId);
long guestOSCategoryId = guestOS.getCategoryId();
GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId);
return guestOSCategory.getName();
}
}

View File

@ -153,5 +153,10 @@ public interface HostDao extends GenericDao<HostVO, Long> {
*/
List<Long> listBy(Long dataCenterId, Long podId, Long clusterId, Type hostType, Status... statuses);
List<HostVO> listBy(Long clusterId, Long podId, long dcId);
List<HostVO> listBy(Long clusterId, Long podId, long dcId);
void loadHostTags(HostVO host);
List<HostVO> listByHostTag(Host.Type type, Long clusterId, Long podId, long dcId, String hostTag);
}

View File

@ -33,6 +33,7 @@ import org.apache.log4j.Logger;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.host.HostTagVO;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.host.Status.Event;
@ -45,6 +46,7 @@ import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
@ -90,7 +92,8 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
protected final Attribute _pingTimeAttr;
protected final DetailsDaoImpl _detailsDao = ComponentLocator.inject(DetailsDaoImpl.class);
protected final HostTagsDaoImpl _hostTagsDao = ComponentLocator.inject(HostTagsDaoImpl.class);
public HostDaoImpl() {
MaintenanceCountSearch = createSearchBuilder();
@ -327,7 +330,39 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
sc.setParameters("dc", dcId);
return listBy(sc);
}
@Override
public List<HostVO> listByHostTag(Host.Type type, Long clusterId, Long podId, long dcId, String hostTag) {
SearchBuilder<HostTagVO> hostTagSearch = _hostTagsDao.createSearchBuilder();
HostTagVO tagEntity = hostTagSearch.entity();
hostTagSearch.and("tag",tagEntity.getTag(), SearchCriteria.Op.EQ);
SearchBuilder<HostVO> hostSearch = createSearchBuilder();
HostVO entity = hostSearch.entity();
hostSearch.and("type", entity.getType(), SearchCriteria.Op.EQ);
hostSearch.and("pod", entity.getPodId(), SearchCriteria.Op.EQ);
hostSearch.and("dc", entity.getDataCenterId(), SearchCriteria.Op.EQ);
hostSearch.and("cluster", entity.getClusterId(), SearchCriteria.Op.EQ);
hostSearch.and("status", entity.getStatus(), SearchCriteria.Op.EQ);
hostSearch.join("hostTagSearch", hostTagSearch, entity.getId(), tagEntity.getHostId(), JoinBuilder.JoinType.INNER);
SearchCriteria<HostVO> sc = hostSearch.create();
sc.setJoinParameters("hostTagSearch", "tag", hostTag);
sc.setParameters("type", type.toString());
if (podId != null) {
sc.setParameters("pod", podId);
}
if (clusterId != null) {
sc.setParameters("cluster", clusterId);
}
sc.setParameters("dc", dcId);
sc.setParameters("status", Status.Up.toString());
return listBy(sc);
}
@Override
public List<HostVO> listByCluster(long clusterId) {
SearchCriteria<HostVO> sc = ClusterSearch.create();
@ -379,7 +414,13 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
Map<String, String> details =_detailsDao.findDetails(host.getId());
host.setDetails(details);
}
@Override
public void loadHostTags(HostVO host){
List<String> hostTags = _hostTagsDao.gethostTags(host.getId());
host.setHostTags(hostTags);
}
@Override
public boolean updateStatus(HostVO host, Event event, long msId) {
Status oldStatus = host.getStatus();
@ -553,7 +594,15 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
return;
}
_detailsDao.persist(host.getId(), details);
}
}
protected void saveHostTags(HostVO host) {
List<String> hostTags = host.getHostTags();
if (hostTags == null || (hostTags != null && hostTags.isEmpty())) {
return;
}
_hostTagsDao.persist(host.getId(), hostTags);
}
@Override @DB
public HostVO persist(HostVO host) {
@ -574,6 +623,8 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
saveDetails(host);
loadDetails(dbHost);
saveHostTags(host);
loadHostTags(dbHost);
txn.commit();
@ -591,6 +642,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
}
saveDetails(host);
saveHostTags(host);
txn.commit();

View File

@ -0,0 +1,31 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.host.dao;
import java.util.List;
import com.cloud.host.HostTagVO;
import com.cloud.utils.db.GenericDao;
public interface HostTagsDao extends GenericDao<HostTagVO, Long> {
void persist(long hostId, List<String> hostTags);
List<String> gethostTags(long hostId);
}

View File

@ -0,0 +1,65 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.host.dao;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Local;
import com.cloud.host.HostTagVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
@Local(value=HostTagsDao.class)
public class HostTagsDaoImpl extends GenericDaoBase<HostTagVO, Long> implements HostTagsDao {
protected final SearchBuilder<HostTagVO> HostSearch;
protected HostTagsDaoImpl() {
HostSearch = createSearchBuilder();
HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
HostSearch.done();
}
@Override
public List<String> gethostTags(long hostId) {
SearchCriteria sc = HostSearch.create();
sc.setParameters("hostId", hostId);
List<HostTagVO> results = search(sc, null);
List<String> hostTags = new ArrayList<String>(results.size());
for (HostTagVO result : results) {
hostTags.add(result.getTag());
}
return hostTags;
}
@Override
public void persist(long hostId, List<String> hostTags) {
Transaction txn = Transaction.currentTxn();
txn.start();
for (String tag : hostTags) {
HostTagVO vo = new HostTagVO(hostId, tag);
persist(vo);
}
txn.commit();
}
}

View File

@ -39,6 +39,9 @@ public class ServiceOffering21VO extends DiskOffering21VO implements ServiceOffe
@Enumerated(EnumType.STRING)
private Network.GuestIpType guestIpType;
@Column(name="host_tag")
private String hostTag;
protected ServiceOffering21VO() {
super();
}
@ -53,6 +56,11 @@ public class ServiceOffering21VO extends DiskOffering21VO implements ServiceOffe
this.offerHA = offerHA;
this.guestIpType = guestIpType;
}
public ServiceOffering21VO(String name, int cpu, int ramSize, int speed, int rateMbps, int multicastRateMbps, boolean offerHA, String displayText, Network.GuestIpType guestIpType, boolean useLocalStorage, boolean recreatable, String tags, String hostTag) {
this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, displayText, guestIpType, useLocalStorage, recreatable, tags);
this.hostTag = hostTag;
}
@Override
public boolean getOfferHA() {
@ -126,4 +134,12 @@ public class ServiceOffering21VO extends DiskOffering21VO implements ServiceOffe
public String gethypervisorType() {
return null;
}
public void setHostTag(String hostTag) {
this.hostTag = hostTag;
}
public String getHostTag() {
return hostTag;
}
}

View File

@ -319,7 +319,7 @@ public class StatsCollector {
capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType);
List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
if (capacities.size() == 0){ // Create a new one
CapacityVO capacity = new CapacityVO(host.getId(), host.getDataCenterId(), host.getPodId(), stats.getByteUsed(), stats.getCapacityBytes(), capacityType);
CapacityVO capacity = new CapacityVO(host.getId(), host.getDataCenterId(), host.getPodId(), host.getClusterId(), stats.getByteUsed(), stats.getCapacityBytes(), capacityType);
_capacityDao.persist(capacity);
}else{ //Update if it already exists.
CapacityVO capacity = capacities.get(0);

View File

@ -50,6 +50,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
@Column(name="ha_enabled")
private boolean offerHA;
@Column(name="host_tag")
private String hostTag;
protected ServiceOfferingVO() {
super();
@ -74,8 +77,13 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
this.multicastRateMbps = multicastRateMbps;
this.offerHA = offerHA;
}
@Override
public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, int rateMbps, int multicastRateMbps, boolean offerHA, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, Long domainId, String hostTag) {
this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, displayText, useLocalStorage, recreatable, tags, systemUse, domainId);
this.hostTag = hostTag;
}
@Override
public boolean getOfferHA() {
return offerHA;
}
@ -138,6 +146,13 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
@Override
public int getMulticastRateMbps() {
return multicastRateMbps;
}
}
public void setHostTag(String hostTag) {
this.hostTag = hostTag;
}
public String getHostTag() {
return hostTag;
}
}

View File

@ -1,187 +1,187 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.storage;
import java.util.List;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.manager.Commands;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientStorageCapacityException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.storage.Volume.VolumeType;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
public interface StorageManager extends Manager {
boolean canVmRestartOnAnotherServer(long vmId);
/** Returns the absolute path of the specified ISO
* @param templateId - the ID of the template that represents the ISO
* @param datacenterId
* @return absolute ISO path
*/
public Pair<String, String> getAbsoluteIsoPath(long templateId, long dataCenterId);
/**
* Returns the URL of the secondary storage host
* @param zoneId
* @return URL
*/
public String getSecondaryStorageURL(long zoneId);
/**
* Returns a comma separated list of tags for the specified storage pool
* @param poolId
* @return comma separated list of tags
*/
public String getStoragePoolTags(long poolId);
/**
* Returns the secondary storage host
* @param zoneId
* @return secondary storage host
*/
public HostVO getSecondaryStorageHost(long zoneId);
/**
* Add a pool to a host
* @param hostId
* @param pool
*/
boolean addPoolToHost(long hostId, StoragePoolVO pool);
/**
* Moves a volume from its current storage pool to a storage pool with enough capacity in the specified zone, pod, or cluster
* @param volume
* @param destPoolDcId
* @param destPoolPodId
* @param destPoolClusterId
* @return VolumeVO
*/
VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType);
/**
* Create a volume based on the given criteria
* @param volume
* @param vm
* @param template
* @param dc
* @param pod
* @param clusterId
* @param offering
* @param diskOffering
* @param avoids
* @param size
* @param hyperType
* @return volume VO if success, null otherwise
*/
VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId,
ServiceOfferingVO offering, DiskOfferingVO diskOffering, List<StoragePoolVO> avoids, long size, HypervisorType hyperType);
/**
* Marks the specified volume as destroyed in the management server database. The expunge thread will delete the volume from its storage pool.
* @param volume
*/
void destroyVolume(VolumeVO volume) throws ConcurrentOperationException;
/** Create capacity entries in the op capacity table
* @param storagePool
*/
public void createCapacityEntry(StoragePoolVO storagePool);
/**
* Checks that the volume is stored on a shared storage pool
* @param volume
* @return true if the volume is on a shared storage pool, false otherwise
*/
boolean volumeOnSharedStoragePool(VolumeVO volume);
Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException;
Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException;
Answer[] sendToPool(long poolId, Commands cmd) throws StorageUnavailableException;
Answer[] sendToPool(StoragePool pool, Commands cmds) throws StorageUnavailableException;
Pair<Long, Answer[]> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Commands cmds) throws StorageUnavailableException;
Pair<Long, Answer> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Command cmd) throws StorageUnavailableException;
/**
* Checks that one of the following is true:
* 1. The volume is not attached to any VM
* 2. The volume is attached to a VM that is running on a host with the KVM hypervisor, and the VM is stopped
* 3. The volume is attached to a VM that is running on a host with the XenServer hypervisor (the VM can be stopped or running)
* @return true if one of the above conditions is true
*/
boolean volumeInactive(VolumeVO volume);
String getVmNameOnVolume(VolumeVO volume);
/**
* Checks if a host has running VMs that are using its local storage pool.
* @return true if local storage is active on the host
*/
boolean isLocalStorageActiveOnHost(Host host);
/**
* Cleans up storage pools by removing unused templates.
* @param recurring - true if this cleanup is part of a recurring garbage collection thread
*/
void cleanupStorage(boolean recurring);
String getPrimaryStorageNameLabel(VolumeVO volume);
/**
* Allocates one volume.
* @param <T>
* @param type
* @param offering
* @param name
* @param size
* @param template
* @param vm
* @param account
* @return VolumeVO a persisted volume.
*/
<T extends VMInstanceVO> DiskProfile allocateRawVolume(VolumeType type, String name, DiskOfferingVO offering, Long size, T vm, Account owner);
<T extends VMInstanceVO> DiskProfile allocateTemplatedVolume(VolumeType type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, Account owner);
void createCapacityEntry(StoragePoolVO storagePool, long allocated);
void prepare(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException;
void release(VirtualMachineProfile<? extends VMInstanceVO> profile);
void cleanupVolumes(long vmId) throws ConcurrentOperationException;
void prepareForMigration(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest);
Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException;
}
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.storage;
import java.util.List;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.manager.Commands;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientStorageCapacityException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.storage.Volume.VolumeType;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
public interface StorageManager extends Manager {
boolean canVmRestartOnAnotherServer(long vmId);
/** Returns the absolute path of the specified ISO
* @param templateId - the ID of the template that represents the ISO
* @param datacenterId
* @return absolute ISO path
*/
public Pair<String, String> getAbsoluteIsoPath(long templateId, long dataCenterId);
/**
* Returns the URL of the secondary storage host
* @param zoneId
* @return URL
*/
public String getSecondaryStorageURL(long zoneId);
/**
* Returns a comma separated list of tags for the specified storage pool
* @param poolId
* @return comma separated list of tags
*/
public String getStoragePoolTags(long poolId);
/**
* Returns the secondary storage host
* @param zoneId
* @return secondary storage host
*/
public HostVO getSecondaryStorageHost(long zoneId);
/**
* Add a pool to a host
* @param hostId
* @param pool
*/
boolean addPoolToHost(long hostId, StoragePoolVO pool);
/**
* Moves a volume from its current storage pool to a storage pool with enough capacity in the specified zone, pod, or cluster
* @param volume
* @param destPoolDcId
* @param destPoolPodId
* @param destPoolClusterId
* @return VolumeVO
*/
VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType);
/**
* Create a volume based on the given criteria
* @param volume
* @param vm
* @param template
* @param dc
* @param pod
* @param clusterId
* @param offering
* @param diskOffering
* @param avoids
* @param size
* @param hyperType
* @return volume VO if success, null otherwise
*/
VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId,
ServiceOfferingVO offering, DiskOfferingVO diskOffering, List<StoragePoolVO> avoids, long size, HypervisorType hyperType);
/**
* Marks the specified volume as destroyed in the management server database. The expunge thread will delete the volume from its storage pool.
* @param volume
*/
void destroyVolume(VolumeVO volume) throws ConcurrentOperationException;
/** Create capacity entries in the op capacity table
* @param storagePool
*/
public void createCapacityEntry(StoragePoolVO storagePool);
/**
* Checks that the volume is stored on a shared storage pool
* @param volume
* @return true if the volume is on a shared storage pool, false otherwise
*/
boolean volumeOnSharedStoragePool(VolumeVO volume);
Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException;
Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException;
Answer[] sendToPool(long poolId, Commands cmd) throws StorageUnavailableException;
Answer[] sendToPool(StoragePool pool, Commands cmds) throws StorageUnavailableException;
Pair<Long, Answer[]> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Commands cmds) throws StorageUnavailableException;
Pair<Long, Answer> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Command cmd) throws StorageUnavailableException;
/**
* Checks that one of the following is true:
* 1. The volume is not attached to any VM
* 2. The volume is attached to a VM that is running on a host with the KVM hypervisor, and the VM is stopped
* 3. The volume is attached to a VM that is running on a host with the XenServer hypervisor (the VM can be stopped or running)
* @return true if one of the above conditions is true
*/
boolean volumeInactive(VolumeVO volume);
String getVmNameOnVolume(VolumeVO volume);
/**
* Checks if a host has running VMs that are using its local storage pool.
* @return true if local storage is active on the host
*/
boolean isLocalStorageActiveOnHost(Host host);
/**
* Cleans up storage pools by removing unused templates.
* @param recurring - true if this cleanup is part of a recurring garbage collection thread
*/
void cleanupStorage(boolean recurring);
String getPrimaryStorageNameLabel(VolumeVO volume);
/**
* Allocates one volume.
* @param <T>
* @param type
* @param offering
* @param name
* @param size
* @param template
* @param vm
* @param account
* @return VolumeVO a persisted volume.
*/
<T extends VMInstanceVO> DiskProfile allocateRawVolume(VolumeType type, String name, DiskOfferingVO offering, Long size, T vm, Account owner);
<T extends VMInstanceVO> DiskProfile allocateTemplatedVolume(VolumeType type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, Account owner);
void createCapacityEntry(StoragePoolVO storagePool, long allocated);
void prepare(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException;
void release(VirtualMachineProfile<? extends VMInstanceVO> profile);
void cleanupVolumes(long vmId) throws ConcurrentOperationException;
void prepareForMigration(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest);
Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException;
}

View File

@ -175,6 +175,7 @@ import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachineProfileImpl;
import com.cloud.vm.dao.ConsoleProxyDao;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.SecondaryStorageVmDao;
@ -330,12 +331,13 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
protected StoragePoolVO findStoragePool(DiskProfile dskCh, final DataCenterVO dc, HostPodVO pod, Long clusterId, final ServiceOffering offering,
final VMInstanceVO vm, final VMTemplateVO template, final Set<StoragePool> avoid) {
VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vm, template, (ServiceOfferingVO)offering, null, null);
Enumeration<StoragePoolAllocator> en = _storagePoolAllocators.enumeration();
while (en.hasMoreElements()) {
final StoragePoolAllocator allocator = en.nextElement();
final StoragePool pool = allocator.allocateToPool(dskCh, dc, pod, clusterId, vm, template, avoid);
if (pool != null) {
return (StoragePoolVO) pool;
final List<StoragePool> poolList = allocator.allocateToPool(dskCh, vmProfile, dc.getId(), pod.getId(), clusterId, avoid, 1);
if (poolList != null && !poolList.isEmpty()) {
return (StoragePoolVO) poolList.get(0);
}
}
return null;
@ -1560,7 +1562,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
if (capacities.size() == 0) {
CapacityVO capacity = new CapacityVO(storagePool.getId(), storagePool.getDataCenterId(), storagePool.getPodId(),
CapacityVO capacity = new CapacityVO(storagePool.getId(), storagePool.getDataCenterId(), storagePool.getPodId(), storagePool.getClusterId(),
storagePool.getAvailableBytes(), storagePool.getCapacityBytes(), CapacityVO.CAPACITY_TYPE_STORAGE);
_capacityDao.persist(capacity);
} else {
@ -1587,7 +1589,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
provFactor = _overProvisioningFactor;
}
if (capacities.size() == 0) {
CapacityVO capacity = new CapacityVO(storagePool.getId(), storagePool.getDataCenterId(), storagePool.getPodId(), allocated,
CapacityVO capacity = new CapacityVO(storagePool.getId(), storagePool.getDataCenterId(), storagePool.getPodId(), storagePool.getClusterId(), allocated,
storagePool.getCapacityBytes() * provFactor, CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED);
_capacityDao.persist(capacity);
} else {
@ -2346,17 +2348,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
return toDiskProfile(vol, offering);
}
protected StoragePool findStorage(DiskProfile dskCh, DeployDestination dest, VirtualMachineProfile<? extends VirtualMachine> vm,
List<? extends Volume> alreadyAllocated, Set<? extends StoragePool> avoid) {
for (StoragePoolAllocator allocator : _storagePoolAllocators) {
StoragePool pool = allocator.allocateTo(dskCh, vm, dest, alreadyAllocated, avoid);
if (pool != null) {
return pool;
}
}
return null;
}
@Override
public void prepareForMigration(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest) {
List<VolumeVO> vols = _volsDao.findUsableVolumesForInstance(vm.getId());
@ -2383,16 +2374,17 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
}
}
@Override
public void prepare(VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest) throws StorageUnavailableException,
InsufficientStorageCapacityException {
List<VolumeVO> vols = _volsDao.findUsableVolumesForInstance(vm.getId());
List<VolumeVO> vols = _volsDao.findUsableVolumesForInstance(vm.getId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Preparing " + vols.size() + " volumes for " + vm);
}
List<VolumeVO> recreateVols = new ArrayList<VolumeVO>(vols.size());
for (VolumeVO vol : vols) {
Volume.State state = vol.getState();
if (state == Volume.State.Ready) {
@ -2436,6 +2428,12 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
} else {
newVol = switchVolume(vol);
newVol.setRecreatable(true);
//update the volume->storagePool map since volumeId has changed
if(dest.getStorageForDisks() != null && dest.getStorageForDisks().containsKey(vol)){
StoragePool poolWithOldVol = dest.getStorageForDisks().get(vol);
dest.getStorageForDisks().put(newVol, poolWithOldVol);
dest.getStorageForDisks().remove(vol);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Created new volume " + newVol + " for old volume " + vol);
}
@ -2503,13 +2501,11 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
template = _templateDao.findById(toBeCreated.getTemplateId());
}
Set<StoragePool> avoids = new HashSet<StoragePool>();
StoragePool pool = null;
while ((pool = findStorage(diskProfile, dest, vm, alreadyCreated, avoids)) != null) {
if(dest.getStorageForDisks() != null){
StoragePool pool = dest.getStorageForDisks().get(toBeCreated);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Trying to create in " + pool);
}
avoids.add(pool);
toBeCreated.setPoolId(pool.getId());
try {
_volsDao.update(toBeCreated, Volume.Event.OperationRetry);
@ -2522,8 +2518,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
VMTemplateStoragePoolVO tmpltStoredOn = null;
tmpltStoredOn = _tmpltMgr.prepareTemplateForCreate(template, pool);
if (tmpltStoredOn == null) {
s_logger.debug("Skipping " + pool + " because we can't propragate template " + template);
continue;
s_logger.debug("Cannot use this pool " + pool + " because we can't propagate template " + template);
return null;
}
cmd = new CreateCommand(diskProfile, tmpltStoredOn.getLocalDownloadPath(), new StorageFilerTO(pool));
} else {

View File

@ -29,10 +29,9 @@ import org.apache.log4j.Logger;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.server.StatsCollector;
@ -47,7 +46,6 @@ import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.Volume.VolumeType;
import com.cloud.storage.dao.StoragePoolDao;
import com.cloud.storage.dao.StoragePoolHostDao;
@ -126,25 +124,48 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
protected boolean poolIsCorrectType(DiskProfile dskCh, StoragePool pool, VMInstanceVO vm) {
boolean localStorageAllocationNeeded = localStorageAllocationNeeded(dskCh, vm);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Is localStorageAllocationNeeded? "+ localStorageAllocationNeeded);
s_logger.debug("Is storage pool shared? "+ pool.getPoolType().isShared());
}
return ((!localStorageAllocationNeeded && pool.getPoolType().isShared()) || (localStorageAllocationNeeded && !pool.getPoolType().isShared()));
}
protected boolean checkPool(Set<? extends StoragePool> avoid, StoragePoolVO pool, DiskProfile dskCh, VMTemplateVO template, List<VMTemplateStoragePoolVO> templatesInPool,
protected boolean checkPool(ExcludeList avoid, StoragePoolVO pool, DiskProfile dskCh, VMTemplateVO template, List<VMTemplateStoragePoolVO> templatesInPool,
VMInstanceVO vm, StatsCollector sc) {
if (avoid.contains(pool)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Checking if storage pool is suitable, name: " + pool.getName()+ " ,poolId: "+ pool.getId());
}
if (avoid.shouldAvoid(pool)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("StoragePool is in avoid set, skipping this pool");
}
return false;
}
if(dskCh.getType().equals(VolumeType.ROOT) && pool.getPoolType().equals(StoragePoolType.Iscsi)){
if (s_logger.isDebugEnabled()) {
s_logger.debug("Disk needed for ROOT volume, but StoragePoolType is Iscsi, skipping this and trying other available pools");
}
return false;
}
//by default, all pools are up when successfully added
//don't return the pool if not up (if in maintenance/prepareformaintenance/errorinmaintenance)
if(!pool.getStatus().equals(StoragePoolStatus.Up))
if(!pool.getStatus().equals(StoragePoolStatus.Up)){
if (s_logger.isDebugEnabled()) {
s_logger.debug("StoragePool status is not UP, status is: "+pool.getStatus().name()+", skipping this pool");
}
return false;
}
// Check that the pool type is correct
if (!poolIsCorrectType(dskCh, pool, vm)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("StoragePool is not of correct type, skipping this pool");
}
return false;
}
@ -154,6 +175,9 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
Long clusterId = pool.getClusterId();
ClusterVO cluster = _clusterDao.findById(clusterId);
if (!(cluster.getHypervisorType() == dskCh.getHypersorType())) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("StoragePool's Cluster does not have required hypervisorType, skipping this pool");
}
return false;
}
@ -229,7 +253,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
if ((pool.getCapacityBytes() * storageOverprovisioningFactor) < (totalAllocatedSize + askingSize)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found pool " + pool.getId() + " for storage, maxSize : " + (pool.getCapacityBytes() * storageOverprovisioningFactor) + ", totalSize : " + totalAllocatedSize + ", askingSize : " + askingSize);
s_logger.debug("Cannot allocate this pool " + pool.getId() + " for storage, not enough storage, maxSize : " + (pool.getCapacityBytes() * storageOverprovisioningFactor) + ", totalSize : " + totalAllocatedSize + ", askingSize : " + askingSize);
}
return false;
@ -243,12 +267,17 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
return storage.getStorageIpAddress();
}
@Override
public StoragePool allocateTo(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, List<? extends Volume> disks, Set<? extends StoragePool> avoids) {
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vm, long dcId, long podId, Long clusterId, Set<? extends StoragePool> avoids, int returnUpTo) {
VMInstanceVO instance = (VMInstanceVO)(vm.getVirtualMachine());
ExcludeList avoid = new ExcludeList();
for(StoragePool pool : avoids){
avoid.addPool(pool.getId());
}
VMTemplateVO template = _templateDao.findById(instance.getTemplateId());
return allocateToPool(dskCh, (DataCenterVO)dest.getDataCenter(), (HostPodVO)dest.getPod(), dest.getCluster().getId(), instance, template, avoids);
DataCenterDeployment plan = new DataCenterDeployment(dcId, podId, clusterId, null);
return allocateToPool(dskCh, vm, plan, avoid, returnUpTo);
}
}

View File

@ -17,22 +17,23 @@
*/
package com.cloud.storage.allocator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.server.StatsCollector;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value=StoragePoolAllocator.class)
public class FirstFitStoragePoolAllocator extends AbstractStoragePoolAllocator {
@ -44,35 +45,57 @@ public class FirstFitStoragePoolAllocator extends AbstractStoragePoolAllocator {
}
@Override
public StoragePool allocateToPool(DiskProfile dskCh, DataCenterVO dc, HostPodVO pod, Long clusterId,
VMInstanceVO vm, VMTemplateVO template, Set<? extends StoragePool> avoid) {
// Check that the allocator type is correct
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
VMInstanceVO vm = (VMInstanceVO)(vmProfile.getVirtualMachine());
VMTemplateVO template = _templateDao.findById(vm.getTemplateId());
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
// Check that the allocator type is correct
if (!allocatorIsCorrectType(dskCh, vm)) {
return null;
return suitablePools;
}
long dcId = plan.getDataCenterId();
long podId = plan.getPodId();
long clusterId = plan.getClusterId();
if(dskCh.getTags() != null && dskCh.getTags().length != 0){
s_logger.debug("Looking for pools in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having tags:" + dskCh.getTags());
}else{
s_logger.debug("Looking for pools in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
}
List<StoragePoolVO> pools = _storagePoolDao.findPoolsByTags(dc.getId(), pod.getId(), clusterId, dskCh.getTags(), null);
List<StoragePoolVO> pools = _storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags(), null);
if (pools.size() == 0) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("No storage pools available for pod id : " + pod.getId());
s_logger.debug("No storage pools available for allocation, returning");
}
return null;
return suitablePools;
}
StatsCollector sc = StatsCollector.getInstance();
Collections.shuffle(pools);
if (s_logger.isDebugEnabled()) {
s_logger.debug("FirstFitStoragePoolAllocator has " + pools.size() + " pools to check for allocation");
}
for (StoragePoolVO pool: pools) {
if(suitablePools.size() == returnUpTo){
break;
}
if (checkPool(avoid, pool, dskCh, template, null, vm, sc)) {
return pool;
suitablePools.add(pool);
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to find any storage pool");
}
s_logger.debug("FirstFitStoragePoolAllocator returning "+suitablePools.size() +" suitable storage pools");
}
return null;
return suitablePools;
}
}

View File

@ -17,9 +17,8 @@
*/
package com.cloud.storage.allocator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
@ -27,14 +26,15 @@ import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value=StoragePoolAllocator.class)
public class GarbageCollectingStoragePoolAllocator extends AbstractStoragePoolAllocator {
@ -60,13 +60,7 @@ public class GarbageCollectingStoragePoolAllocator extends AbstractStoragePoolAl
}
@Override
public StoragePool allocateToPool(DiskProfile dskCh,
DataCenterVO dc,
HostPodVO pod,
Long clusterId,
VMInstanceVO vm,
VMTemplateVO template,
Set<? extends StoragePool> avoid) {
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
if (!_storagePoolCleanupEnabled) {
s_logger.debug("Storage pool cleanup is not enabled, so GarbageCollectingStoragePoolAllocator is being skipped.");
@ -75,7 +69,7 @@ public class GarbageCollectingStoragePoolAllocator extends AbstractStoragePoolAl
// Clean up all storage pools
_storageMgr.cleanupStorage(false);
VMInstanceVO vm = (VMInstanceVO)(vmProfile.getVirtualMachine());
// Determine what allocator to use
StoragePoolAllocator allocator;
if (localStorageAllocationNeeded(dskCh, vm)) {
@ -85,12 +79,9 @@ public class GarbageCollectingStoragePoolAllocator extends AbstractStoragePoolAl
}
// Try to find a storage pool after cleanup
Set<StoragePool> myAvoids = new HashSet<StoragePool>();
for (StoragePool pool : avoid) {
myAvoids.add(pool);
}
ExcludeList myAvoids = new ExcludeList(avoid.getDataCentersToAvoid(), avoid.getPodsToAvoid(), avoid.getClustersToAvoid(), avoid.getHostsToAvoid(), avoid.getPoolsToAvoid());
return allocator.allocateToPool(dskCh, dc, pod, clusterId, vm, template, myAvoids);
return allocator.allocateToPool(dskCh, vmProfile, plan, myAvoids, returnUpTo);
}
@Override

View File

@ -17,10 +17,9 @@
*/
package com.cloud.storage.allocator;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
@ -30,14 +29,13 @@ import org.apache.log4j.Logger;
import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.offering.ServiceOffering;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.utils.DateUtil;
@ -54,7 +52,6 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachineProfileImpl;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
@ -89,54 +86,69 @@ public class LocalStoragePoolAllocator extends FirstFitStoragePoolAllocator {
}
@Override
public StoragePool allocateToPool(DiskProfile dskCh,
DataCenterVO dc,
HostPodVO pod,
Long clusterId,
VMInstanceVO vm,
VMTemplateVO template,
Set<? extends StoragePool> avoid) {
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
VMInstanceVO vm = (VMInstanceVO)(vmProfile.getVirtualMachine());
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
// Check that the allocator type is correct
if (!allocatorIsCorrectType(dskCh, vm)) {
return null;
return suitablePools;
}
Set<StoragePool> myAvoids = new HashSet<StoragePool>(avoid);
VirtualMachineProfile<VMInstanceVO> vmc = new VirtualMachineProfileImpl<VMInstanceVO>(vm.getType());
StoragePool pool = null;
while ((pool = super.allocateToPool(dskCh, dc, pod, clusterId, vm, template, myAvoids)) != null) {
myAvoids.add(pool);
ExcludeList myAvoids = new ExcludeList(avoid.getDataCentersToAvoid(), avoid.getPodsToAvoid(), avoid.getClustersToAvoid(), avoid.getHostsToAvoid(), avoid.getPoolsToAvoid());
if (s_logger.isDebugEnabled()) {
s_logger.debug("LocalStoragePoolAllocator trying to find storage pool to fit the vm");
}
List<StoragePool> availablePool;
while (!(availablePool = super.allocateToPool(dskCh, vmProfile, plan, myAvoids, 1)).isEmpty()) {
StoragePool pool = availablePool.get(0);
myAvoids.addPool(pool.getId());
if (pool.getPoolType().isShared()) {
return pool;
suitablePools.add(pool);
}else{
List<StoragePoolHostVO> hostsInSPool = _poolHostDao.listByPoolId(pool.getId());
assert(hostsInSPool.size() == 1) : "Local storage pool should be one host per pool";
StoragePoolHostVO spHost = hostsInSPool.get(0);
SearchCriteria<Long> sc = VmsOnPoolSearch.create();
sc.setJoinParameters("volumeJoin", "poolId", pool.getId());
sc.setParameters("state", State.Expunging);
List<Long> vmsOnHost = _vmInstanceDao.customSearchIncludingRemoved(sc, null);
if(s_logger.isDebugEnabled()) {
s_logger.debug("Found " + vmsOnHost.size() + " VM instances are alloacated at host " + spHost.getHostId() + " with local storage pool " + pool.getName());
for(Long vmId : vmsOnHost) {
s_logger.debug("VM " + vmId + " is allocated on host " + spHost.getHostId() + " with local storage pool " + pool.getName());
}
}
if(hostHasCpuMemoryCapacity(spHost.getHostId(), vmsOnHost, vm)) {
s_logger.debug("Found suitable local storage pool " + pool.getId() + ", adding to list");
suitablePools.add(pool);
}else{
s_logger.debug("Found pool " + pool.getId() + " but host doesn't fit, skipping this pool");
}
}
List<StoragePoolHostVO> hostsInSPool = _poolHostDao.listByPoolId(pool.getId());
assert(hostsInSPool.size() == 1) : "Local storage pool should be one host per pool";
StoragePoolHostVO spHost = hostsInSPool.get(0);
SearchCriteria<Long> sc = VmsOnPoolSearch.create();
sc.setJoinParameters("volumeJoin", "poolId", pool.getId());
sc.setParameters("state", State.Expunging);
List<Long> vmsOnHost = _vmInstanceDao.customSearchIncludingRemoved(sc, null);
if(s_logger.isDebugEnabled()) {
s_logger.debug("Found " + vmsOnHost.size() + " VM instances are alloacated at host " + spHost.getHostId() + " with local storage pool " + pool.getName());
for(Long vmId : vmsOnHost) {
s_logger.debug("VM " + vmId + " is allocated on host " + spHost.getHostId() + " with local storage pool " + pool.getName());
}
if(suitablePools.size() == returnUpTo){
break;
}
if(hostHasCpuMemoryCapacity(spHost.getHostId(), vmsOnHost, vm)) {
return pool;
}
s_logger.debug("Found pool " + pool.getId() + " but host doesn't fit.");
}
s_logger.debug("Unable to find storage pool to fit the vm");
return null;
if (s_logger.isDebugEnabled()) {
s_logger.debug("LocalStoragePoolAllocator returning "+suitablePools.size() +" suitable storage pools");
}
if(suitablePools.isEmpty()){
if (s_logger.isDebugEnabled()) {
s_logger.debug("Unable to find storage pool to fit the vm");
}
}
return suitablePools;
}
private boolean hostHasCpuMemoryCapacity(long hostId, List<Long> vmOnHost, VMInstanceVO vm) {

View File

@ -17,22 +17,24 @@
*/
package com.cloud.storage.allocator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.server.StatsCollector;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value=StoragePoolAllocator.class)
public class RandomStoragePoolAllocator extends AbstractStoragePoolAllocator {
@ -44,33 +46,47 @@ public class RandomStoragePoolAllocator extends AbstractStoragePoolAllocator {
}
@Override
public StoragePool allocateToPool(DiskProfile dskCh,
DataCenterVO dc, HostPodVO pod, Long clusterId, VMInstanceVO vm,
VMTemplateVO template, Set<? extends StoragePool> avoid) {
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
List<StoragePool> suitablePools = new ArrayList<StoragePool>();
VMInstanceVO vm = (VMInstanceVO)(vmProfile.getVirtualMachine());
VMTemplateVO template = _templateDao.findById(vm.getTemplateId());
// Check that the allocator type is correct
if (!allocatorIsCorrectType(dskCh, vm)) {
return null;
return suitablePools;
}
List<StoragePoolVO> pools = _storagePoolDao.listBy(dc.getId(), pod.getId(), clusterId);
long dcId = plan.getDataCenterId();
long podId = plan.getPodId();
long clusterId = plan.getClusterId();
s_logger.debug("Looking for pools in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
List<StoragePoolVO> pools = _storagePoolDao.listBy(dcId, podId, clusterId);
if (pools.size() == 0) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("No storage pools available for pod id : " + pod.getId());
s_logger.debug("No storage pools available for allocation, returning");
}
return null;
return suitablePools;
}
StatsCollector sc = StatsCollector.getInstance();
Collections.shuffle(pools);
if (s_logger.isDebugEnabled()) {
s_logger.debug("RandomStoragePoolAllocator has " + pools.size() + " pools to check for allocation");
}
for (StoragePoolVO pool: pools) {
if(suitablePools.size() == returnUpTo){
break;
}
if (checkPool(avoid, pool, dskCh, template, null, vm, sc)) {
return pool;
suitablePools.add(pool);
}
}
return null;
if (s_logger.isDebugEnabled()) {
s_logger.debug("RandomStoragePoolAllocator returning "+suitablePools.size() +" suitable storage pools");
}
return suitablePools;
}
}

View File

@ -19,17 +19,12 @@ package com.cloud.storage.allocator;
import java.util.List;
import java.util.Set;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.utils.component.Adapter;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@ -39,9 +34,20 @@ import com.cloud.vm.VirtualMachineProfile;
*/
public interface StoragePoolAllocator extends Adapter {
StoragePool allocateToPool(DiskProfile dskCh, DataCenterVO dc, HostPodVO pod, Long cluster, VMInstanceVO vm, VMTemplateVO template, Set<? extends StoragePool> avoids);
//keeping since storageMgr is using this API for some existing functionalities
List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vm, long dcId, long podId, Long clusterId, Set<? extends StoragePool> avoids, int returnUpTo);
String chooseStorageIp(VirtualMachine vm, Host host, Host storage);
StoragePool allocateTo(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, List<? extends Volume> disks, Set<? extends StoragePool> avoids);
/**
* Determines which storage pools are suitable for the guest virtual machine
*
* @param DiskProfile dskCh
* @param VirtualMachineProfile vmProfile
* @param DeploymentPlan plan
* @param ExcludeList avoid
* @param int returnUpTo (use -1 to return all possible pools)
* @return List<StoragePool> List of storage pools that are suitable for the VM
**/
List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vm, DeploymentPlan plan, ExcludeList avoid, int returnUpTo);
}

View File

@ -17,36 +17,36 @@
*/
package com.cloud.storage.allocator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume.VolumeType;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
@Local(value=StoragePoolAllocator.class)
public class UseLocalForRootAllocator extends LocalStoragePoolAllocator implements StoragePoolAllocator {
boolean _useLocalStorage;
@Override
public StoragePool allocateToPool(DiskProfile dskCh, DataCenterVO dc, HostPodVO pod, Long clusterId, VMInstanceVO vm, VMTemplateVO template, Set<? extends StoragePool> avoids) {
public List<StoragePool> allocateToPool(DiskProfile dskCh, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
if (!_useLocalStorage) {
return null;
}
return super.allocateToPool(dskCh, dc, pod, clusterId, vm, template, avoids);
return super.allocateToPool(dskCh, vmProfile, plan, avoid, returnUpTo);
}
@Override

View File

@ -57,4 +57,6 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long> {
List<VolumeVO> listVolumesToBeDestroyed();
ImageFormat getImageFormat(Long volumeId);
List<VolumeVO> findReadyRootVolumesByInstance(long instanceId);
}

View File

@ -58,7 +58,6 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
protected final GenericSearchBuilder<VolumeVO, SumCount> TotalSizeByPoolSearch;
protected final GenericSearchBuilder<VolumeVO, Long> ActiveTemplateSearch;
protected final SearchBuilder<VolumeVO> InstanceStatesSearch;
protected final SearchBuilder<VolumeVO> AllFieldsSearch;
protected final Attribute _stateAttr;
@ -163,6 +162,15 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
return listIncludingRemovedBy(sc);
}
@Override
public List<VolumeVO> findReadyRootVolumesByInstance(long instanceId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", instanceId);
sc.setParameters("state", Volume.State.Ready);
sc.setParameters("vType", Volume.VolumeType.ROOT.toString());
return listIncludingRemovedBy(sc);
}
@Override
public List<VolumeVO> findByAccountAndPod(long accountId, long podId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
@ -326,7 +334,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
InstanceStatesSearch.and("instance", InstanceStatesSearch.entity().getInstanceId(), Op.EQ);
InstanceStatesSearch.and("states", InstanceStatesSearch.entity().getState(), Op.IN);
InstanceStatesSearch.done();
_stateAttr = _allAttributes.get("state");
assert _stateAttr != null : "Couldn't get the state attribute";
}

View File

@ -33,6 +33,7 @@ import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.agent.AgentManager.OnError;
import com.cloud.agent.Listener;
@ -102,11 +103,14 @@ import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.Volume.VolumeType;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.StoragePoolDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.user.Account;
@ -171,6 +175,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
@Inject protected HighAvailabilityManager _haMgr;
@Inject protected HostPodDao _podDao;
@Inject protected DataCenterDao _dcDao;
@Inject protected StoragePoolDao _storagePoolDao;
@Inject protected HypervisorGuruManager _hvGuruMgr;
@Inject(adapter=DeploymentPlanner.class)
@ -542,8 +547,27 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
ExcludeList avoids = new ExcludeList();
int retry = _retry;
while (retry-- != 0) { // It's != so that it can match -1.
//edit plan if this vm's ROOT volume is in READY state already
List<VolumeVO> vols = _volsDao.findReadyRootVolumesByInstance(vm.getId());
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, null, params);
for (VolumeVO vol : vols) {
Volume.State state = vol.getState();
if (state == Volume.State.Ready) {
StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId());
if (!pool.isInMaintenance()) {
long rootVolDcId = pool.getDataCenterId();
Long rootVolPodId = pool.getPodId();
Long rootVolClusterId = pool.getClusterId();
plan = new DataCenterDeployment(rootVolDcId, rootVolPodId, rootVolClusterId, vol.getPoolId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Root Volume " + vol + " is ready, changing deployment plan to use this pool's datacenterId: "+rootVolDcId +" , podId: "+rootVolPodId +" , and clusterId: "+rootVolClusterId);
}
}
}
}
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, account, params);
DeployDestination dest = null;
for (DeploymentPlanner planner : _planners) {
dest = planner.plan(vmProfile, plan, avoids);
@ -566,7 +590,6 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
}
try {
_storageMgr.prepare(vmProfile, dest);
_networkMgr.prepare(vmProfile, dest, ctx);
@ -579,6 +602,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
vmGuru.finalizeDeployment(cmds, vmProfile, dest, ctx);
vm.setPodId(dest.getPod().getId());
work = _workDao.findById(work.getId());
if (work == null || work.getStep() != Step.Prepare) {
throw new ConcurrentOperationException("Work steps have been changed: " + work);

View File

@ -68,4 +68,6 @@ public interface UserVmDao extends GenericDao<UserVmVO, Long> {
void saveDetails(UserVmVO vm);
List<Long> listPodIdsHavingVmsforAccount(long zoneId, long accountId);
}

View File

@ -17,6 +17,10 @@
*/
package com.cloud.vm.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -25,13 +29,21 @@ import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.capacity.CapacityVO;
import com.cloud.host.HostVO;
import com.cloud.uservm.UserVm;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.Attribute;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.NicVO;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine.State;
@ -54,8 +66,14 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
protected final SearchBuilder<UserVmVO> DestroySearch;
protected SearchBuilder<UserVmVO> AccountDataCenterVirtualSearch;
protected GenericSearchBuilder<UserVmVO, Long> CountByAccountPod;
protected GenericSearchBuilder<UserVmVO, Long> PodsHavingVmsForAccount;
protected SearchBuilder<UserVmVO> UserVmSearch;
protected final Attribute _updateTimeAttr;
private static final String LIST_PODS_HAVING_VMS_FOR_ACCOUNT = "SELECT pod_id FROM cloud.vm_instance WHERE data_center_id = ? AND account_id = ? AND pod_id IS NOT NULL GROUP BY pod_id HAVING count(id) > 0 ORDER BY count(id) DESC";
protected final UserVmDetailsDaoImpl _detailsDao = ComponentLocator.inject(UserVmDetailsDaoImpl.class);
@ -119,6 +137,12 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
AccountHostSearch.and("hostId", AccountHostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
AccountHostSearch.done();
CountByAccountPod = createSearchBuilder(Long.class);
CountByAccountPod.select(null, Func.COUNT, null);
CountByAccountPod.and("account", CountByAccountPod.entity().getAccountId(), SearchCriteria.Op.EQ);
CountByAccountPod.and("pod", CountByAccountPod.entity().getPodId(), SearchCriteria.Op.EQ);
CountByAccountPod.done();
_updateTimeAttr = _allAttributes.get("updateTime");
assert _updateTimeAttr != null : "Couldn't get this updateTime attribute";
}
@ -278,4 +302,28 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
}
_detailsDao.persist(vm.getId(), details);
}
@Override
public List<Long> listPodIdsHavingVmsforAccount(long zoneId, long accountId){
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
List<Long> result = new ArrayList<Long>();
try {
String sql = LIST_PODS_HAVING_VMS_FOR_ACCOUNT;
pstmt = txn.prepareAutoCloseStatement(sql);
pstmt.setLong(1, zoneId);
pstmt.setLong(2, accountId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result.add(rs.getLong(1));
}
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + LIST_PODS_HAVING_VMS_FOR_ACCOUNT, e);
} catch (Throwable e) {
throw new CloudRuntimeException("Caught: " + LIST_PODS_HAVING_VMS_FOR_ACCOUNT, e);
}
}
}

View File

@ -987,6 +987,7 @@ CREATE TABLE `cloud`.`op_host_capacity` (
`host_id` bigint unsigned,
`data_center_id` bigint unsigned NOT NULL,
`pod_id` bigint unsigned,
`cluster_id` bigint unsigned COMMENT 'foreign key to cluster',
`used_capacity` bigint unsigned NOT NULL,
`reserved_capacity` bigint unsigned NOT NULL,
`total_capacity` bigint unsigned NOT NULL,
@ -996,7 +997,9 @@ CREATE TABLE `cloud`.`op_host_capacity` (
CONSTRAINT `fk_op_host_capacity__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `host_pod_ref` (`id`) ON DELETE CASCADE,
INDEX `i_op_host_capacity__pod_id`(`pod_id`),
CONSTRAINT `fk_op_host_capacity__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE,
INDEX `i_op_host_capacity__data_center_id`(`data_center_id`)
INDEX `i_op_host_capacity__data_center_id`(`data_center_id`),
CONSTRAINT `fk_op_host_capacity__cluster_id` FOREIGN KEY `fk_op_host_capacity__cluster_id` (`cluster_id`) REFERENCES `cloud`.`cluster`(`id`) ON DELETE CASCADE,
INDEX `i_op_host_capacity__cluster_id`(`cluster_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`alert` (

View File

@ -18,7 +18,9 @@
package com.cloud.utils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
// StringUtils exists in Apache Commons Lang, but rather than import the entire JAR to our system, for now
// just implement the method needed
@ -37,5 +39,47 @@ public class StringUtils {
}
}
return sb.toString();
}
}
/**
* Converts a comma separated list of tags to a List
* @param tags
* @return List of tags
*/
public static List<String> csvTagsToList(String tags) {
List<String> tagsList = new ArrayList<String>();
if (tags != null) {
String[] tokens = tags.split(",");
for (int i = 0; i < tokens.length; i++) {
tagsList.add(tokens[i].trim());
}
}
return tagsList;
}
/**
* Converts a List of tags to a comma separated list
* @param tags
* @return String containing a comma separated list of tags
*/
public static String listToCsvTags(List<String> tagsList) {
String tags = "";
if (tagsList.size() > 0) {
for (int i = 0; i < tagsList.size(); i++) {
tags += tagsList.get(i);
if (i != tagsList.size() - 1) {
tags += ",";
}
}
}
return tags;
}
}