From 7fa053370ed2aee537abd80bce7068205a3656dc Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 1 Mar 2011 17:47:37 -0800 Subject: [PATCH] Bug 8208 - bare metal provisioning Add bare metal planner --- api/src/com/cloud/api/ApiConstants.java | 1 + .../com/cloud/api/commands/AddHostCmd.java | 15 +++- .../com/cloud/deploy/DeploymentPlanner.java | 11 +++ .../com/cloud/offering/ServiceOffering.java | 1 - client/tomcatconf/components.xml.in | 1 + .../cloud/agent/manager/AgentManagerImpl.java | 4 + .../baremetal/LinMinPxeServerManagerImpl.java | 6 +- .../com/cloud/deploy/BareMetalPlanner.java | 80 +++++++++++++++++++ .../src/com/cloud/deploy/FirstFitPlanner.java | 9 ++- .../src/com/cloud/deploy/SimplePlanner.java | 8 ++ .../com/cloud/service/ServiceOfferingVO.java | 1 - .../cloud/vm/VirtualMachineManagerImpl.java | 6 +- .../cloud/vm/VirtualMachineProfileImpl.java | 4 + 13 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 server/src/com/cloud/deploy/BareMetalPlanner.java diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 64ba091020b..2486d949a61 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -194,6 +194,7 @@ public class ApiConstants { public static final String HOST_CPU_NUM = "hostcpunum"; public static final String HOST_MEM_CAPACITY = "hostmemcapacity"; public static final String HOST_MAC = "hostmac"; + public static final String HOST_TAG = "hosttag"; public static final String PXE_SERVER_TYPE = "pxeservertype"; public static final String LINMIN_USERNAME = "linminusername"; public static final String LINMIN_PASSWORD = "linminpassword"; diff --git a/api/src/com/cloud/api/commands/AddHostCmd.java b/api/src/com/cloud/api/commands/AddHostCmd.java index 9a6bdc184b2..13e1b73b3ba 100644 --- a/api/src/com/cloud/api/commands/AddHostCmd.java +++ b/api/src/com/cloud/api/commands/AddHostCmd.java @@ -66,18 +66,21 @@ 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_CPU_CAPACITY, type=CommandType.LONG, description="HZ per CPU of host") + @Parameter(name=ApiConstants.HOST_CPU_CAPACITY, type=CommandType.LONG, description="Only for hypervisor is BareMetal, HZ per CPU of host") private Long cpuCapacity; - @Parameter(name=ApiConstants.HOST_CPU_NUM, type=CommandType.LONG, description="number of CPU on host") + @Parameter(name=ApiConstants.HOST_CPU_NUM, type=CommandType.LONG, description="Only for hypervisor is BareMetal, number of CPU on host") private Long cpuNum; - @Parameter(name=ApiConstants.HOST_MEM_CAPACITY, type=CommandType.LONG, description="memory capacity of host") + @Parameter(name=ApiConstants.HOST_MEM_CAPACITY, type=CommandType.LONG, description="Only for hypervisor is BareMetal, memory capacity of host(in MB)") private Long memCapacity; - @Parameter(name=ApiConstants.HOST_MAC, type=CommandType.STRING, required=true, description="Mac of PXE nic") + @Parameter(name=ApiConstants.HOST_MAC, type=CommandType.STRING, description="Only for hypervisor is BareMetal, Mac of PXE nic") private String mac; + @Parameter(name=ApiConstants.HOST_TAG, type=CommandType.STRING, description="Only for hypervisor is BareMetal, Tag of host") + private String hostTag; + @@ -133,6 +136,10 @@ public class AddHostCmd extends BaseCmd { return mac; } + public String getHostTag() { + return hostTag; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/com/cloud/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java index a93b484f771..7ae8c337a33 100644 --- a/api/src/com/cloud/deploy/DeploymentPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentPlanner.java @@ -44,6 +44,17 @@ public interface DeploymentPlanner extends Adapter { */ boolean check(VirtualMachineProfile vm, DeploymentPlan plan, DeployDestination dest, ExcludeList exclude); + /** + * canHandle is called before plan to determine if the plan can do the allocation. Planers should be exclusive so planner writer must + * make sure only one planer->canHandle return true in the planner list + * + * @param vm virtual machine. + * @param plan deployment plan that tells you where it's being deployed to. + * @param avoid avoid these data centers, pods, clusters, or hosts. + * @return true if it's okay to allocate; false or not + */ + boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid); + public static class ExcludeList { Set _dcIds; Set _podIds; diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java index 57c5d0e49e5..572953aca26 100755 --- a/api/src/com/cloud/offering/ServiceOffering.java +++ b/api/src/com/cloud/offering/ServiceOffering.java @@ -73,5 +73,4 @@ public interface ServiceOffering { boolean getUseLocalStorage(); Long getDomainId(); - } diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index 1d45a537924..bb160ed7a4b 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -78,6 +78,7 @@ + diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 237088283e7..de6ad88d954 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -754,6 +754,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Long cpuCapacity = cmd.getCpuCapacity(); Long cpuNum = cmd.getCpuNum(); String mac = cmd.getMac(); + String hostTag = cmd.getHostTag(); MapbareMetalParams = new HashMap(); // this is for standalone option @@ -779,6 +780,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, bareMetalParams.put("cpuCapacity", cpuCapacity.toString()); bareMetalParams.put("memCapacity", memCapacity.toString()); bareMetalParams.put("mac", mac); + if (hostTag != null) { + bareMetalParams.put("hostTag", hostTag); + } } diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java index b56a89e14ca..c8fe4bc0c96 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java @@ -64,15 +64,15 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements apiPassword = cmd.getLinMinPassword(); apid = cmd.getLinMinApid(); if (apiUsername == null) { - throw new InvalidParameterValueException("No LinMin username specified, without it I can user LinMin API"); + throw new InvalidParameterValueException("No LinMin username specified, without it I can not use LinMin API"); } if (apiPassword == null) { - throw new InvalidParameterValueException("No LinMin password specified, without it I can user LinMin API"); + throw new InvalidParameterValueException("No LinMin password specified, without it I can not use LinMin API"); } if (apid == null) { - throw new InvalidParameterValueException("No LinMin apid specified, without it I can user LinMin API"); + throw new InvalidParameterValueException("No LinMin apid specified, without it I can not use LinMin API"); } String ipAddress = uri.getHost(); diff --git a/server/src/com/cloud/deploy/BareMetalPlanner.java b/server/src/com/cloud/deploy/BareMetalPlanner.java new file mode 100644 index 00000000000..e1319997967 --- /dev/null +++ b/server/src/com/cloud/deploy/BareMetalPlanner.java @@ -0,0 +1,80 @@ +package com.cloud.deploy; + +import java.util.List; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.ServiceOffering; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfileImpl; + +@Local(value=DeploymentPlanner.class) +public class BareMetalPlanner extends FirstFitPlanner implements DeploymentPlanner { + private static final Logger s_logger = Logger.getLogger(BareMetalPlanner.class); + + @Override + public DeployDestination plan(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid) throws InsufficientServerCapacityException { + VirtualMachine vm = vmProfile.getVirtualMachine(); + ServiceOffering offering = vmProfile.getServiceOffering(); + String hostTag = null; + + if (offering.getTags() != null) { + String[] tags = offering.getTags().split(","); + if (tags.length > 0) { + hostTag = tags[0]; + } + } + + if (hostTag != null) { + List hosts = _hostDao.listBy(Host.Type.Routing, vm.getDataCenterId()); + HostVO target = null; + for (HostVO h : hosts) { + _hostDao.loadDetails(h); + if (h.getDetail("hostTag") != null && h.getDetail("hostTag").equalsIgnoreCase(hostTag)) { + target = h; + break; + } + } + + if (target == null) { + s_logger.warn("Cannot find host with tag " + hostTag); + return null; + } + + int cpu = target.getCpus(); + int speed = target.getSpeed().intValue(); + Long ramSize = target.getTotalMemory() / (1024L*1024L); + ServiceOfferingVO newOffering = new ServiceOfferingVO(offering.getName(), cpu, ramSize.intValue(), speed, offering.getRateMbps(), + offering.getMulticastRateMbps(), false, offering.getDisplayText(), offering.getUseLocalStorage(), false, offering.getTags(), false); + ((VirtualMachineProfileImpl)vmProfile).setServiceOffering(newOffering); + } + + DeployDestination dest = super.plan(vmProfile, plan, avoid); + + if (hostTag == null && dest != null) { + Host h = dest.getHost(); + if (h.getCpus() != offering.getCpu() || h.getTotalMemory() != offering.getRamSize() || h.getSpeed() != offering.getSpeed()) { + throw new CloudRuntimeException(String.format("Bare Metal only allows one VM one host, " + + "the offering capcacity doesn't equal to host capacity(offering: cpu number:%$1s, cpu speed:%$2s," + + "ram size:%3$s; host: cpu number:%$4s, cpu speed:%$5s, ram size:%$6s)", offering.getCpu(), offering.getSpeed(), + offering.getRamSize(), h.getCpus(), h.getSpeed(), h.getTotalMemory())); + } + } + + return dest; + } + + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return vm.getHypervisorType() == HypervisorType.BareMetal; + } +} diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 9a26d6404a9..ddd3753b260 100644 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -20,6 +20,7 @@ import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.host.DetailVO; import com.cloud.host.Host; @@ -27,6 +28,7 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.DetailsDao; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.storage.GuestOSCategoryVO; @@ -43,7 +45,7 @@ import com.cloud.vm.VirtualMachineProfile; @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 protected HostDao _hostDao; @Inject private CapacityDao _capacityDao; @Inject private DataCenterDao _dcDao; @Inject private HostPodDao _podDao; @@ -286,4 +288,9 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId); return guestOSCategory.getName(); } + + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return vm.getHypervisorType() != HypervisorType.BareMetal; + } } diff --git a/server/src/com/cloud/deploy/SimplePlanner.java b/server/src/com/cloud/deploy/SimplePlanner.java index 35beb8d86fa..e309daff268 100644 --- a/server/src/com/cloud/deploy/SimplePlanner.java +++ b/server/src/com/cloud/deploy/SimplePlanner.java @@ -26,12 +26,14 @@ import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.org.Cluster; import com.cloud.utils.component.Inject; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @Local(value=DeploymentPlanner.class) @@ -68,4 +70,10 @@ public class SimplePlanner extends PlannerBase implements DeploymentPlanner { protected SimplePlanner() { super(); } + + //TODO: set it to true if you want to use it + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return false; + } } diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/server/src/com/cloud/service/ServiceOfferingVO.java index 7c4b0d0626a..05d8de301e7 100644 --- a/server/src/com/cloud/service/ServiceOfferingVO.java +++ b/server/src/com/cloud/service/ServiceOfferingVO.java @@ -139,5 +139,4 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public int getMulticastRateMbps() { return multicastRateMbps; } - } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 45c676da67b..d98a9c04ba3 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -560,7 +560,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, null, params); DeployDestination dest = null; for (DeploymentPlanner planner : _planners) { - dest = planner.plan(vmProfile, plan, avoids); + if (planner.canHandle(vmProfile, plan, avoids)) { + dest = planner.plan(vmProfile, plan, avoids); + } else { + continue; + } if (dest != null) { avoids.addHost(dest.getHost().getId()); journal.record("Deployment found ", vmProfile, dest); diff --git a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java index ecb826501fb..265e314870c 100644 --- a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java @@ -229,4 +229,8 @@ public class VirtualMachineProfileImpl implements Virtua public Map getParameters() { return _params; } + + public void setServiceOffering(ServiceOfferingVO offering) { + _offering = offering; + } }