From b313b7c85235c59b5d93d87e9cc43d93c1ead3e7 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 22 Feb 2011 19:07:07 -0800 Subject: [PATCH 01/11] Add bare metal stuff to addHost command add ipmi.py --- api/src/com/cloud/api/ApiConstants.java | 2 + .../com/cloud/api/commands/AddHostCmd.java | 16 +++ api/src/com/cloud/hypervisor/Hypervisor.java | 6 +- scripts/util/ipmi.py | 109 ++++++++++++++++++ .../cloud/agent/manager/AgentManagerImpl.java | 32 ++++- server/src/com/cloud/resource/Discoverer.java | 1 + .../com/cloud/resource/DiscovererBase.java | 5 + 7 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 scripts/util/ipmi.py diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 62dd6cfaa51..d860962cf16 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -190,5 +190,7 @@ public class ApiConstants { public static final String IS_SYSTEM = "issystem"; public static final String AVAILABILITY = "availability"; public static final String NETWORKRATE = "networkrate"; + public static final String HOST_CPU_CAPACITY = "hostcpucapacity"; + public static final String HOST_MEM_CAPACITY = "hostmemcapacity"; } diff --git a/api/src/com/cloud/api/commands/AddHostCmd.java b/api/src/com/cloud/api/commands/AddHostCmd.java index e73eb037864..95802676c16 100644 --- a/api/src/com/cloud/api/commands/AddHostCmd.java +++ b/api/src/com/cloud/api/commands/AddHostCmd.java @@ -65,6 +65,14 @@ 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="CPU capacity of host") + private Long cpuCapacity; + + @Parameter(name=ApiConstants.HOST_MEM_CAPACITY, type=CommandType.LONG, description="memory capacity of host") + private Long memCapacity; + + ///////////////////////////////////////////////////// @@ -103,6 +111,14 @@ public class AddHostCmd extends BaseCmd { return hypervisor; } + public Long getCpuCapacity() { + return cpuCapacity; + } + + public Long getMemCapacity() { + return memCapacity; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/com/cloud/hypervisor/Hypervisor.java b/api/src/com/cloud/hypervisor/Hypervisor.java index 8e3805ea93b..a759050c36a 100644 --- a/api/src/com/cloud/hypervisor/Hypervisor.java +++ b/api/src/com/cloud/hypervisor/Hypervisor.java @@ -27,6 +27,8 @@ public class Hypervisor { VMware, VirtualBox, Parralels, + BareMetal, + Any; /*If you don't care about the hypervisor type*/ public static HypervisorType getType(String hypervisor) { @@ -46,9 +48,11 @@ public class Hypervisor { return HypervisorType.VirtualBox; } else if (hypervisor.equalsIgnoreCase("Parralels")) { return HypervisorType.Parralels; + }else if (hypervisor.equalsIgnoreCase("BareMetal")) { + return HypervisorType.BareMetal; } else if (hypervisor.equalsIgnoreCase("Any")) { return HypervisorType.Any; - } else { + } else { return HypervisorType.None; } } diff --git a/scripts/util/ipmi.py b/scripts/util/ipmi.py new file mode 100644 index 00000000000..9fc4674a155 --- /dev/null +++ b/scripts/util/ipmi.py @@ -0,0 +1,109 @@ +#!/usr/bin/python + +import sys, os, subprocess, errno, re +from os.path import exists + +TOOl_PATH = "/usr/bin/ipmitool" + +try: + from subprocess import check_call + from subprocess import CalledProcessError +except ImportError: + def check_call(*popenargs, **kwargs): + import subprocess + retcode = subprocess.call(*popenargs, **kwargs) + cmd = kwargs.get("args") + if cmd is None: cmd = popenargs[0] + if retcode: raise CalledProcessError(retcode, cmd) + return retcode + + class CalledProcessError(Exception): + def __init__(self, returncode, cmd): + self.returncode = returncode ; self.cmd = cmd + def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) + +class Command: + def __init__(self,name,parent=None): + self.__name = name + self.__parent = parent + def __getattr__(self,name): + if name == "_print": name = "print" + return Command(name,self) + def __call__(self,*args): + class CommandOutput: + def __init__(self,ret,stdout,stderr): + self.stdout = stdout + self.stderr = stderr + self.ret = ret + + cmd = self.__get_recursive_name() + list(args) + #print " ",cmd + popen = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + m = popen.communicate() + ret = popen.wait() + return CommandOutput(ret,*m) + def __get_recursive_name(self,sep=None): + m = self + l = [] + while m is not None: + l.append(m.__name) + m = m.__parent + l.reverse() + if sep: return sep.join(l) + else: return l + def __str__(self): + return ''%self.__get_recursive_name(sep=" ") + + def __repr__(self): return self.__str__() + + +ipmitool = Command("ipmitool") + +def check_tool(): + if exists(TOOl_PATH) == False: + print "Can not find ipmitool" + return False + +def ping(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + + if hostname == None: + print "No hostname" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "status") + if o.ret: + print o.stderr + return 1 + else: + return 0 + +call_table = {"ping":ping} +def dispatch(args): + cmd = args[1] + params = args[2:] + func_params = {} + + if call_table.has_key(cmd) == False: + print "No function %s" % cmd + return 1 + + for p in params: + pairs = p.split("=") + if len(pairs) != 2: + print "Invalid parameter %s" % p + return 1 + func_params[pairs[0]] = pairs[1] + + func = call_table[cmd] + return func(func_params) + +if __name__ == "__main__": + if check_tool() == False: + sys.exit(1) + if len(sys.argv) < 2: + print "Not enough arguments, at least one" + sys.exit(1) + sys.exit(dispatch(sys.argv)) diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 0a18d6e44c0..41caf97c5bf 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -749,12 +749,30 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, String url = cmd.getUrl(); String username = cmd.getUsername(); String password = cmd.getPassword(); + Long memCapacity = cmd.getMemCapacity(); + Long cpuCapacity = cmd.getCpuCapacity(); + MapbareMetalParams = new HashMap(); + // this is for standalone option if (clusterName == null && clusterId == null) { clusterName = "Standalone-" + url; } - return discoverHosts(dcId, podId, clusterId, clusterName, url, - username, password, cmd.getHypervisor()); + + if (cmd.getHypervisor().equalsIgnoreCase(Hypervisor.HypervisorType.BareMetal.toString())) { + if (memCapacity == null) { + memCapacity = Long.valueOf(0); + } + if (cpuCapacity == null) { + cpuCapacity = Long.valueOf(0); + } + + bareMetalParams.put("cpuCapacity", cpuCapacity.toString()); + bareMetalParams.put("memCapacity", memCapacity.toString()); + } + + + return discoverHostsFull(dcId, podId, clusterId, clusterName, url, + username, password, cmd.getHypervisor(), bareMetalParams); } @Override @@ -772,6 +790,14 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, String clusterName, String url, String username, String password, String hypervisorType) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { + return discoverHostsFull(dcId, podId, clusterId, clusterName, url, username, password, hypervisorType, null); + } + + + private List discoverHostsFull(Long dcId, Long podId, Long clusterId, + String clusterName, String url, String username, String password, + String hypervisorType, Mapparams) throws IllegalArgumentException, + DiscoveryException, InvalidParameterValueException { URI uri = null; // Check if the zone exists in the system @@ -865,6 +891,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, boolean isHypervisorTypeSupported = false; while (en.hasMoreElements()) { Discoverer discoverer = en.nextElement(); + discoverer.putParam(params); + if (!discoverer.matchHypervisor(hypervisorType)) { continue; } diff --git a/server/src/com/cloud/resource/Discoverer.java b/server/src/com/cloud/resource/Discoverer.java index eba1aaf7c61..8d92a47d44e 100644 --- a/server/src/com/cloud/resource/Discoverer.java +++ b/server/src/com/cloud/resource/Discoverer.java @@ -45,4 +45,5 @@ public interface Discoverer extends Adapter { boolean matchHypervisor(String hypervisor); Hypervisor.HypervisorType getHypervisorType(); + public void putParam(Map params); } diff --git a/server/src/com/cloud/resource/DiscovererBase.java b/server/src/com/cloud/resource/DiscovererBase.java index 77678c53f91..5681635cf83 100644 --- a/server/src/com/cloud/resource/DiscovererBase.java +++ b/server/src/com/cloud/resource/DiscovererBase.java @@ -44,6 +44,11 @@ public abstract class DiscovererBase implements Discoverer { return null; } + + @Override + public void putParam(Map params) { + _params.putAll(params); + } @Override public String getName() { From 828f8c94938ba6c318a055057ddc4e136bd596ae Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 23 Feb 2011 17:20:43 -0800 Subject: [PATCH 02/11] Bug 8208 - bare metal provisioning Able to add cluster and host --- api/src/com/cloud/api/ApiConstants.java | 4 +++- api/src/com/cloud/api/commands/AddHostCmd.java | 16 +++++++++++++++- .../cloud/agent/manager/AgentManagerImpl.java | 16 ++++++++++++++-- .../src/com/cloud/resource/DiscovererBase.java | 4 ++++ .../com/cloud/resource/DummyHostDiscoverer.java | 6 ++++++ .../com/cloud/storage/dao/VMTemplateDaoImpl.java | 6 +++++- 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index d860962cf16..65477ce9967 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -191,6 +191,8 @@ public class ApiConstants { public static final String AVAILABILITY = "availability"; public static final String NETWORKRATE = "networkrate"; public static final String HOST_CPU_CAPACITY = "hostcpucapacity"; - public static final String HOST_MEM_CAPACITY = "hostmemcapacity"; + public static final String HOST_CPU_NUM = "hostcpunum"; + public static final String HOST_MEM_CAPACITY = "hostmemcapacity"; + public static final String HOST_MAC = "hostmac"; } diff --git a/api/src/com/cloud/api/commands/AddHostCmd.java b/api/src/com/cloud/api/commands/AddHostCmd.java index 95802676c16..9a6bdc184b2 100644 --- a/api/src/com/cloud/api/commands/AddHostCmd.java +++ b/api/src/com/cloud/api/commands/AddHostCmd.java @@ -66,12 +66,18 @@ 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="CPU capacity of host") + @Parameter(name=ApiConstants.HOST_CPU_CAPACITY, type=CommandType.LONG, description="HZ per CPU of host") private Long cpuCapacity; + @Parameter(name=ApiConstants.HOST_CPU_NUM, type=CommandType.LONG, description="number of CPU on host") + private Long cpuNum; + @Parameter(name=ApiConstants.HOST_MEM_CAPACITY, type=CommandType.LONG, description="memory capacity of host") private Long memCapacity; + @Parameter(name=ApiConstants.HOST_MAC, type=CommandType.STRING, required=true, description="Mac of PXE nic") + private String mac; + @@ -115,10 +121,18 @@ public class AddHostCmd extends BaseCmd { return cpuCapacity; } + public Long getCpuNum() { + return cpuNum; + } + public Long getMemCapacity() { return memCapacity; } + public String getMac() { + return mac; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 41caf97c5bf..c95e5e375f8 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -751,6 +751,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, String password = cmd.getPassword(); Long memCapacity = cmd.getMemCapacity(); Long cpuCapacity = cmd.getCpuCapacity(); + Long cpuNum = cmd.getCpuNum(); + String mac = cmd.getMac(); MapbareMetalParams = new HashMap(); // this is for standalone option @@ -765,9 +767,17 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, if (cpuCapacity == null) { cpuCapacity = Long.valueOf(0); } + if (cpuNum == null) { + cpuNum = Long.valueOf(0); + } + if (mac == null) { + mac = "unknown"; + } + bareMetalParams.put("cpuNum", cpuNum.toString()); bareMetalParams.put("cpuCapacity", cpuCapacity.toString()); bareMetalParams.put("memCapacity", memCapacity.toString()); + bareMetalParams.put("mac", mac); } @@ -891,7 +901,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, boolean isHypervisorTypeSupported = false; while (en.hasMoreElements()) { Discoverer discoverer = en.nextElement(); - discoverer.putParam(params); + if (params != null) { + discoverer.putParam(params); + } if (!discoverer.matchHypervisor(hypervisorType)) { continue; @@ -2684,7 +2696,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, // If this command is from a KVM agent, or from an agent that has a // null hypervisor type, don't do the CIDR check if (hypervisorType == null || hypervisorType == HypervisorType.KVM - || hypervisorType == HypervisorType.VMware) { + || hypervisorType == HypervisorType.VMware || hypervisorType == HypervisorType.BareMetal) { doCidrCheck = false; } diff --git a/server/src/com/cloud/resource/DiscovererBase.java b/server/src/com/cloud/resource/DiscovererBase.java index 5681635cf83..03ac483a537 100644 --- a/server/src/com/cloud/resource/DiscovererBase.java +++ b/server/src/com/cloud/resource/DiscovererBase.java @@ -18,6 +18,7 @@ package com.cloud.resource; import java.net.URL; +import java.util.HashMap; import java.util.Map; import javax.naming.ConfigurationException; @@ -47,6 +48,9 @@ public abstract class DiscovererBase implements Discoverer { @Override public void putParam(Map params) { + if (_params == null) { + _params = new HashMap(); + } _params.putAll(params); } diff --git a/server/src/com/cloud/resource/DummyHostDiscoverer.java b/server/src/com/cloud/resource/DummyHostDiscoverer.java index a50c5eb1c33..def7167eab6 100644 --- a/server/src/com/cloud/resource/DummyHostDiscoverer.java +++ b/server/src/com/cloud/resource/DummyHostDiscoverer.java @@ -103,5 +103,11 @@ public class DummyHostDiscoverer implements Discoverer { @Override public void postDiscovery(List hosts, long msId) { //do nothing + } + + @Override + public void putParam(Map params) { + // TODO Auto-generated method stub + } } diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index b14941ea0f1..79cd61d807f 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -441,7 +441,11 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem List tmplts = listBy(sc); Collections.shuffle(tmplts); - return tmplts.get(0); + if (tmplts.size() > 0) { + return tmplts.get(0); + } else { + return null; + } } @Override From f82dec999d89de7085239ba94085b9e34c347af3 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 24 Feb 2011 14:07:10 -0800 Subject: [PATCH 03/11] Bug 8208 - bare metal provisioning complete createVirtualMachine method --- api/src/com/cloud/api/BaseCmd.java | 3 + .../com/cloud/api/commands/DeployVMCmd.java | 16 +- api/src/com/cloud/storage/Storage.java | 3 +- api/src/com/cloud/vm/BareMetalVmService.java | 4 + .../DefaultComponentLibrary.java | 3 + .../cloud/template/TemplateManagerImpl.java | 40 +-- .../src/com/cloud/vm/BareMetalVmManager.java | 5 + .../com/cloud/vm/BareMetalVmManagerImpl.java | 280 ++++++++++++++++++ .../src/com/cloud/vm/UserVmManagerImpl.java | 2 +- .../cloud/vm/VirtualMachineManagerImpl.java | 4 +- 10 files changed, 337 insertions(+), 23 deletions(-) create mode 100644 api/src/com/cloud/vm/BareMetalVmService.java create mode 100644 server/src/com/cloud/vm/BareMetalVmManager.java create mode 100644 server/src/com/cloud/vm/BareMetalVmManagerImpl.java diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java index 26fc9adb01c..81bfd9092c6 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -53,6 +53,7 @@ import com.cloud.user.UserContext; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLocator; import com.cloud.vm.UserVmService; +import com.cloud.vm.BareMetalVmService; public abstract class BaseCmd { private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName()); @@ -109,6 +110,7 @@ public abstract class BaseCmd { public static RulesService _rulesService; public static LoadBalancingRulesService _lbService; public static RemoteAccessVpnService _ravService; + public static BareMetalVmService _bareMetalVmService; static void setComponents(ResponseGenerator generator) { @@ -130,6 +132,7 @@ public abstract class BaseCmd { _lbService = locator.getManager(LoadBalancingRulesService.class); _ravService = locator.getManager(RemoteAccessVpnService.class); _responseGenerator = generator; + _bareMetalVmService = locator.getManager(BareMetalVmService.class); } public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException; diff --git a/api/src/com/cloud/api/commands/DeployVMCmd.java b/api/src/com/cloud/api/commands/DeployVMCmd.java index 661bceab051..cd7bc5c1b9b 100644 --- a/api/src/com/cloud/api/commands/DeployVMCmd.java +++ b/api/src/com/cloud/api/commands/DeployVMCmd.java @@ -35,6 +35,7 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; @@ -228,7 +229,12 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { UserVm result; try { UserContext.current().setEventDetails("Vm Id: "+getEntityId()); - result = _userVmService.startVirtualMachine(this); + if (getHypervisor() == HypervisorType.BareMetal) { + result = _bareMetalVmService.startVirtualMachine(this); + } else { + result = _userVmService.startVirtualMachine(this); + } + if (result != null) { UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); @@ -252,7 +258,13 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { - UserVm result = _userVmService.createVirtualMachine(this); + UserVm result; + if (getHypervisor() == HypervisorType.BareMetal) { + result = _bareMetalVmService.createVirtualMachine(this); + } else { + result = _userVmService.createVirtualMachine(this); + } + if (result != null){ setEntityId(result.getId()); } else { diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index 5e5adb27b48..66b4c1c0a8e 100644 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -23,7 +23,8 @@ public class Storage { RAW(false, false, false), VHD(true, true, true), ISO(false, false, false), - OVA(true, true, true, "ova"); + OVA(true, true, true, "ova"), + BAREMETAL(false, false, false); private final boolean thinProvisioned; private final boolean supportSparse; diff --git a/api/src/com/cloud/vm/BareMetalVmService.java b/api/src/com/cloud/vm/BareMetalVmService.java new file mode 100644 index 00000000000..eed95666d99 --- /dev/null +++ b/api/src/com/cloud/vm/BareMetalVmService.java @@ -0,0 +1,4 @@ +package com.cloud.vm; + +public interface BareMetalVmService extends UserVmService { +} diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index a94fa8182f9..2d8ea99e074 100644 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -147,6 +147,8 @@ import com.cloud.vm.dao.SecondaryStorageVmDaoImpl; import com.cloud.vm.dao.UserVmDaoImpl; import com.cloud.vm.dao.UserVmDetailsDaoImpl; import com.cloud.vm.dao.VMInstanceDaoImpl; +import com.cloud.vm.BareMetalVmManagerImpl;; + public class DefaultComponentLibrary implements ComponentLibrary { @@ -323,6 +325,7 @@ public class DefaultComponentLibrary implements ComponentLibrary { addManager("ClusteredAgentManager", ClusteredAgentManagerImpl.class); addManager("VirtualMachineManager", ClusteredVirtualMachineManagerImpl.class); addManager("HypervisorGuruManager", HypervisorGuruManagerImpl.class); + addManager("BareMetalVmManager", BareMetalVmManagerImpl.class); ComponentInfo info = addManager("ConsoleProxyManager", ConsoleProxyManagerImpl.class); info.addParameter("consoleproxy.sslEnabled", "true"); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 8c2db9bc5e7..927d4bb2e6f 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -349,7 +349,8 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) - &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz"))){ + &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) + &&hypervisorType != HypervisorType.BareMetal){ throw new InvalidParameterValueException("Please specify a valid "+format.toLowerCase()); } @@ -381,25 +382,28 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } URI uri = new URI(url); - if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) { + if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file") && !uri.getScheme().equalsIgnoreCase("baremetal"))) { throw new IllegalArgumentException("Unsupported scheme for url: " + url); } - int port = uri.getPort(); - if (!(port == 80 || port == 443 || port == -1)) { - throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); - } - String host = uri.getHost(); - try { - InetAddress hostAddr = InetAddress.getByName(host); - if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress() ) { - throw new IllegalArgumentException("Illegal host specified in url"); - } - if (hostAddr instanceof Inet6Address) { - throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); - } - } catch (UnknownHostException uhe) { - throw new IllegalArgumentException("Unable to resolve " + host); - } + + if (!uri.getScheme().equalsIgnoreCase("baremetal")) { + int port = uri.getPort(); + if (!(port == 80 || port == 443 || port == -1)) { + throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); + } + String host = uri.getHost(); + try { + InetAddress hostAddr = InetAddress.getByName(host); + if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) { + throw new IllegalArgumentException("Illegal host specified in url"); + } + if (hostAddr instanceof Inet6Address) { + throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); + } + } catch (UnknownHostException uhe) { + throw new IllegalArgumentException("Unable to resolve " + host); + } + } // Check that the resource limit for templates/ISOs won't be exceeded UserVO user = _userDao.findById(userId); diff --git a/server/src/com/cloud/vm/BareMetalVmManager.java b/server/src/com/cloud/vm/BareMetalVmManager.java new file mode 100644 index 00000000000..9e952a4dccb --- /dev/null +++ b/server/src/com/cloud/vm/BareMetalVmManager.java @@ -0,0 +1,5 @@ +package com.cloud.vm; + +public interface BareMetalVmManager extends UserVmManager { + +} diff --git a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java new file mode 100644 index 00000000000..3238e573947 --- /dev/null +++ b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java @@ -0,0 +1,280 @@ +package com.cloud.vm; + +import java.util.ArrayList; +import java.util.List; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.cloud.api.commands.AttachVolumeCmd; +import com.cloud.api.commands.CreateTemplateCmd; +import com.cloud.api.commands.DeployVMCmd; +import com.cloud.api.commands.DetachVolumeCmd; +import com.cloud.api.commands.UpgradeVMCmd; +import com.cloud.configuration.ResourceCount.ResourceType; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.domain.DomainVO; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventVO; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Network; +import com.cloud.network.NetworkVO; +import com.cloud.network.Networks.TrafficType; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.storage.Storage; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; +import com.cloud.storage.Storage.TemplateType; +import com.cloud.user.Account; +import com.cloud.user.SSHKeyPair; +import com.cloud.user.UserContext; +import com.cloud.uservm.UserVm; +import com.cloud.utils.Pair; +import com.cloud.utils.component.Manager; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; + +@Local(value={BareMetalVmManager.class, BareMetalVmService.class}) +public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMetalVmManager, BareMetalVmService, Manager { + private static final Logger s_logger = Logger.getLogger(BareMetalVmManagerImpl.class); + + @Override + public boolean attachISOToVM(long vmId, long isoId, boolean attach) { + s_logger.warn("attachISOToVM is not supported by Bare Metal, just fake a true"); + return true; + } + + @Override + public Volume attachVolumeToVM(AttachVolumeCmd command) { + s_logger.warn("attachVolumeToVM is not supported by Bare Metal, return null"); + return null; + } + + @Override + public Volume detachVolumeFromVM(DetachVolumeCmd cmd) { + s_logger.warn("detachVolumeFromVM is not supported by Bare Metal, return null"); + return null; + } + + @Override + public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) { + s_logger.warn("upgradeVirtualMachine is not supported by Bare Metal, return null"); + return null; + } + + @Override + public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, ResourceAllocationException { + s_logger.warn("createPrivateTemplateRecord is not supported by Bare Metal, return null"); + return null; + } + + @Override @DB + public VMTemplateVO createPrivateTemplate(CreateTemplateCmd command) throws CloudRuntimeException { + s_logger.warn("createPrivateTemplate is not supported by Bare Metal, return null"); + return null; + } + + @Override + public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, + StorageUnavailableException, ResourceAllocationException { + Account caller = UserContext.current().getCaller(); + + String accountName = cmd.getAccountName(); + Long domainId = cmd.getDomainId(); + List networkList = cmd.getNetworkIds(); + String group = cmd.getGroup(); + + Account owner = _accountDao.findActiveAccount(accountName, domainId); + if (owner == null) { + throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId); + } + + _accountMgr.checkAccess(caller, owner); + long accountId = owner.getId(); + + DataCenterVO dc = _dcDao.findById(cmd.getZoneId()); + if (dc == null) { + throw new InvalidParameterValueException("Unable to find zone: " + cmd.getZoneId()); + } + + if (dc.getDomainId() != null) { + DomainVO domain = _domainDao.findById(dc.getDomainId()); + if (domain == null) { + throw new CloudRuntimeException("Unable to find the domain " + dc.getDomainId() + " for the zone: " + dc); + } + _accountMgr.checkAccess(caller, domain); + _accountMgr.checkAccess(owner, domain); + } + + // check if account/domain is with in resource limits to create a new vm + if (_accountMgr.resourceLimitExceeded(owner, ResourceType.user_vm)) { + ResourceAllocationException rae = new ResourceAllocationException("Maximum number of virtual machines for account: " + owner.getAccountName() + + " has been exceeded."); + rae.setResourceType("vm"); + throw rae; + } + + ServiceOfferingVO offering = _serviceOfferingDao.findById(cmd.getServiceOfferingId()); + if (offering == null || offering.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find service offering: " + cmd.getServiceOfferingId()); + } + + VMTemplateVO template = _templateDao.findById(cmd.getTemplateId()); + // Make sure a valid template ID was specified + if (template == null || template.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to use template " + cmd.getTemplateId()); + } + + if (template.getTemplateType().equals(TemplateType.SYSTEM)) { + throw new InvalidParameterValueException("Unable to use system template " + cmd.getTemplateId()+" to deploy a user vm"); + } + + if (template.getFormat() != Storage.ImageFormat.BAREMETAL) { + throw new InvalidParameterValueException("Unable to use non Bare Metal template" + cmd.getTemplateId() +" to deploy a bare metal vm"); + } + + String userData = cmd.getUserData(); + byte [] decodedUserData = null; + if (userData != null) { + if (userData.length() >= 2 * MAX_USER_DATA_LENGTH_BYTES) { + throw new InvalidParameterValueException("User data is too long"); + } + decodedUserData = org.apache.commons.codec.binary.Base64.decodeBase64(userData.getBytes()); + if (decodedUserData.length > MAX_USER_DATA_LENGTH_BYTES){ + throw new InvalidParameterValueException("User data is too long"); + } + if (decodedUserData.length < 1) { + throw new InvalidParameterValueException("User data is too short"); + } + } + + // Find an SSH public key corresponding to the key pair name, if one is given + String sshPublicKey = null; + if (cmd.getSSHKeyPairName() != null && !cmd.getSSHKeyPairName().equals("")) { + Account account = UserContext.current().getCaller(); + SSHKeyPair pair = _sshKeyPairDao.findByName(account.getAccountId(), account.getDomainId(), cmd.getSSHKeyPairName()); + if (pair == null) { + throw new InvalidParameterValueException("A key pair with name '" + cmd.getSSHKeyPairName() + "' was not found."); + } + + sshPublicKey = pair.getPublicKey(); + } + + _accountMgr.checkAccess(caller, template); + + DataCenterDeployment plan = new DataCenterDeployment(dc.getId()); + + s_logger.debug("Allocating in the DB for bare metal vm"); + + if (dc.getNetworkType() != NetworkType.Basic || networkList != null) { + s_logger.warn("Bare Metal only supports basical network mode now, switch to baisc network automatically"); + } + + Network defaultNetwork = _networkMgr.getSystemNetworkByZoneAndTrafficType(dc.getId(), TrafficType.Guest); + if (defaultNetwork == null) { + throw new InvalidParameterValueException("Unable to find a default network to start a vm"); + } + + networkList = new ArrayList(); + networkList.add(defaultNetwork.getId()); + + List> networks = new ArrayList>(); + short defaultNetworkNumber = 0; + for (Long networkId : networkList) { + NetworkVO network = _networkDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Unable to find network by id " + networkId); + } else { + if (!network.isShared()) { + //Check account permissions + List networkMap = _networkDao.listBy(accountId, networkId); + if (networkMap == null || networkMap.isEmpty()) { + throw new PermissionDeniedException("Unable to create a vm using network with id " + networkId + ", permission denied"); + } + } + + if (network.isDefault()) { + defaultNetworkNumber++; + } + networks.add(new Pair(network, null)); + } + } + + //at least one network default network has to be set + if (defaultNetworkNumber == 0) { + throw new InvalidParameterValueException("At least 1 default network has to be specified for the vm"); + } else if (defaultNetworkNumber >1) { + throw new InvalidParameterValueException("Only 1 default network per vm is supported"); + } + + long id = _vmDao.getNextInSequence(Long.class, "id"); + + String hostName = cmd.getName(); + String instanceName = VirtualMachineName.getVmName(id, owner.getId(), _instance); + if (hostName == null) { + hostName = instanceName; + } else { + //verify hostName (hostname doesn't have to be unique) + if (!NetUtils.verifyDomainNameLabel(hostName, true)) { + throw new InvalidParameterValueException("Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); + } + } + + UserVmVO vm = new UserVmVO(id, instanceName, cmd.getDisplayName(), template.getId(), HypervisorType.BareMetal, + template.getGuestOSId(), offering.getOfferHA(), domainId, owner.getId(), offering.getId(), userData, hostName); + + if (sshPublicKey != null) { + vm.setDetail("SSH.PublicKey", sshPublicKey); + } + + if (_itMgr.allocate(vm, template, offering, null, null, networks, null, plan, cmd.getHypervisor(), owner) == null) { + return null; + } + + _vmDao.saveDetails(vm); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully allocated DB entry for " + vm); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully allocated DB entry for " + vm); + } + UserContext.current().setEventDetails("Vm Id: " + vm.getId()); + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, accountId, dc.getId(), vm.getId(), vm.getName(), offering.getId(), + template.getId(), null); + _usageEventDao.persist(usageEvent); + + _accountMgr.incrementResourceCount(accountId, ResourceType.user_vm); + + // Assign instance to the group + try { + if (group != null) { + boolean addToGroup = addInstanceToGroup(Long.valueOf(id), group); + if (!addToGroup) { + throw new CloudRuntimeException("Unable to assign Vm to the group " + group); + } + } + } catch (Exception ex) { + throw new CloudRuntimeException("Unable to assign Vm to the group " + group); + } + + return vm; + } + + public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { + return null; + } +} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index e221e58a0bf..0104af99c2c 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1848,7 +1848,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } } - private boolean validPassword(String password) { + protected boolean validPassword(String password) { if (password == null || password.length() == 0) { return false; } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 06f3274d8d7..f5de5cccd1f 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -246,9 +246,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene if (template.getFormat() == ImageFormat.ISO) { _storageMgr.allocateRawVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner); - } else { + } else if (template.getFormat() == ImageFormat.BAREMETAL) { + }else { _storageMgr.allocateTemplatedVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner); } + for (Pair offering : dataDiskOfferings) { _storageMgr.allocateRawVolume(VolumeType.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner); } From 5035778b1a9b5f93c74754758a8dec2d2fcd8a0d Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 24 Feb 2011 19:22:34 -0800 Subject: [PATCH 04/11] Bug 8208 - bare metal provisioning StartCommand cloud reach to BareMetalResrouce --- api/src/com/cloud/network/Network.java | 2 + api/src/com/cloud/vm/VirtualMachine.java | 8 +- client/tomcatconf/components.xml.in | 1 + .../com/cloud/hypervisor/BareMetalGuru.java | 37 ++++++++ .../cloud/network/element/DhcpElement.java | 2 + .../com/cloud/vm/BareMetalVmManagerImpl.java | 94 ++++++++++++++++++- .../cloud/vm/VirtualMachineManagerImpl.java | 18 +++- 7 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 server/src/com/cloud/hypervisor/BareMetalGuru.java diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 4a1cc9538f1..d2e0ebaf59d 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -73,6 +73,8 @@ public interface Network extends ControlledEntity { public static final Provider DhcpServer = new Provider("DhcpServer"); public static final Provider JuniperSRX = new Provider("JuniperSRX"); public static final Provider F5BigIp = new Provider("F5BigIp"); + public static final Provider ExternalDhcpServer = new Provider("ExternalDhcpServer"); + public static final Provider ExternalGateWay = new Provider("ExternalGateWay"); private String name; diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index a5449faef97..cbf64da9483 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -145,7 +145,13 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, StateObject User, DomainRouter, ConsoleProxy, - SecondaryStorageVm + SecondaryStorageVm, + + /* + * UserBareMetal is only used for selecting VirtualMachineGuru, there is no + * VM with this type. UserBareMetal should treat exactly as User. + */ + UserBareMetal, } public String getInstanceName(); diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index 0b8886962de..1d45a537924 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -69,6 +69,7 @@ + diff --git a/server/src/com/cloud/hypervisor/BareMetalGuru.java b/server/src/com/cloud/hypervisor/BareMetalGuru.java new file mode 100644 index 00000000000..3c400cb4613 --- /dev/null +++ b/server/src/com/cloud/hypervisor/BareMetalGuru.java @@ -0,0 +1,37 @@ +package com.cloud.hypervisor; + +import javax.ejb.Local; + +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.utils.component.Inject; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +@Local(value=HypervisorGuru.class) +public class BareMetalGuru extends HypervisorGuruBase implements HypervisorGuru { + @Inject GuestOSDao _guestOsDao; + + protected BareMetalGuru() { + super(); + } + + @Override + public HypervisorType getHypervisorType() { + return HypervisorType.BareMetal; + } + + @Override + public VirtualMachineTO implement(VirtualMachineProfile vm) { + VirtualMachineTO to = toVirtualMachineTO(vm); + + // Determine the VM's OS description + GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId()); + to.setOs(guestOS.getDisplayName()); + + return to; + } + +} diff --git a/server/src/com/cloud/network/element/DhcpElement.java b/server/src/com/cloud/network/element/DhcpElement.java index e51304ee0e2..849bebb63dc 100644 --- a/server/src/com/cloud/network/element/DhcpElement.java +++ b/server/src/com/cloud/network/element/DhcpElement.java @@ -80,6 +80,8 @@ public class DhcpElement extends AdapterBase implements NetworkElement, Password if (provider.equalsIgnoreCase(Provider.JuniperSRX.getName()) && ipType == GuestIpType.Virtual) { return true; + } else if (dc.getDhcpProvider().equalsIgnoreCase(Provider.ExternalDhcpServer.getName())){ + return false; } else { if (dc.getNetworkType() == NetworkType.Basic) { return (ipType == GuestIpType.Direct && trafficType == TrafficType.Guest); diff --git a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java index 3238e573947..59a71cb7caa 100644 --- a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java @@ -2,20 +2,26 @@ package com.cloud.vm; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; import javax.ejb.Local; +import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.agent.manager.Commands; import com.cloud.api.commands.AttachVolumeCmd; import com.cloud.api.commands.CreateTemplateCmd; import com.cloud.api.commands.DeployVMCmd; import com.cloud.api.commands.DetachVolumeCmd; import com.cloud.api.commands.UpgradeVMCmd; import com.cloud.configuration.ResourceCount.ResourceType; +import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeployDestination; import com.cloud.domain.DomainVO; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventVO; @@ -39,15 +45,20 @@ import com.cloud.user.Account; import com.cloud.user.SSHKeyPair; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; +import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Manager; +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +import com.cloud.vm.VirtualMachine.Type; @Local(value={BareMetalVmManager.class, BareMetalVmService.class}) public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMetalVmManager, BareMetalVmService, Manager { private static final Logger s_logger = Logger.getLogger(BareMetalVmManagerImpl.class); + private ConfigurationDao _configDao; @Override public boolean attachISOToVM(long vmId, long isoId, boolean attach) { @@ -275,6 +286,87 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet } public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { - return null; + return super.startVirtualMachine(cmd); + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + + ComponentLocator locator = ComponentLocator.getCurrentLocator(); + _configDao = locator.getDao(ConfigurationDao.class); + if (_configDao == null) { + throw new ConfigurationException("Unable to get the configuration dao."); + } + + Map configs = _configDao.getConfiguration("AgentManager", params); + + _instance = configs.get("instance.name"); + if (_instance == null) { + _instance = "DEFAULT"; + } + + String workers = configs.get("expunge.workers"); + int wrks = NumbersUtil.parseInt(workers, 10); + + String time = configs.get("expunge.interval"); + _expungeInterval = NumbersUtil.parseInt(time, 86400); + + time = configs.get("expunge.delay"); + _expungeDelay = NumbersUtil.parseInt(time, _expungeInterval); + + _executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger")); + + _itMgr.registerGuru(Type.UserBareMetal, this); + + s_logger.info("User VM Manager is configured."); + + return true; + } + + @Override + public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { + UserVmVO vm = profile.getVirtualMachine(); + Account owner = _accountDao.findById(vm.getAccountId()); + + if (owner == null || owner.getState() == Account.State.disabled) { + throw new PermissionDeniedException("The owner of " + vm + " either does not exist or is disabled: " + vm.getAccountId()); + } + + return true; + } + + @Override + public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { + UserVmVO userVm = profile.getVirtualMachine(); + List nics = _nicDao.listByVmId(userVm.getId()); + for (NicVO nic : nics) { + NetworkVO network = _networkDao.findById(nic.getNetworkId()); + if (network.getTrafficType() == TrafficType.Guest) { + userVm.setPrivateIpAddress(nic.getIp4Address()); + userVm.setPrivateMacAddress(nic.getMacAddress()); + } + } + _vmDao.update(userVm.getId(), userVm); + return true; + } + + @Override + public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) { + UserVmVO vm = profile.getVirtualMachine(); + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_START, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), + vm.getServiceOfferingId(), vm.getTemplateId(), null); + _usageEventDao.persist(usageEvent); + + List nics = _nicDao.listByVmId(vm.getId()); + for (NicVO nic : nics) { + NetworkVO network = _networkDao.findById(nic.getNetworkId()); + long isDefault = (nic.isDefaultNic()) ? 1 : 0; + usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_CREATE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), + network.getNetworkOfferingId(), null, isDefault); + _usageEventDao.persist(usageEvent); + } + + return true; } } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index f5de5cccd1f..a61d9411145 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -130,6 +130,7 @@ import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.ItWorkVO.Step; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; @@ -296,6 +297,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene return (VirtualMachineGuru)_vmGurus.get(vm.getType()); } + @SuppressWarnings("unchecked") + private VirtualMachineGuru getBareMetalVmGuru(T vm) { + return (VirtualMachineGuru)_vmGurus.get(Type.UserBareMetal); + } + @Override public boolean expunge(T vm, User caller, Account account) throws ResourceUnavailableException { try { @@ -521,7 +527,13 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene public T advanceStart(T vm, Map params, User caller, Account account) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { long vmId = vm.getId(); - VirtualMachineGuru vmGuru = getVmGuru(vm); + VirtualMachineGuru vmGuru; + if (vm.getHypervisorType() == HypervisorType.BareMetal) { + vmGuru = getBareMetalVmGuru(vm); + } else { + vmGuru = getVmGuru(vm); + } + vm = vmGuru.findById(vm.getId()); Ternary start = changeToStartState(vmGuru, vm, caller, account); if (start == null) { @@ -569,7 +581,9 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene try { - _storageMgr.prepare(vmProfile, dest); + if (vm.getHypervisorType() != HypervisorType.BareMetal) { + _storageMgr.prepare(vmProfile, dest); + } _networkMgr.prepare(vmProfile, dest, ctx); vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx); From a9728998ffc1fce9aef8bd4808b05fbee7d7853d Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 25 Feb 2011 18:58:07 -0800 Subject: [PATCH 05/11] Bug 8208 - bare metal provisioning Successfully add start entry into LinMin PXE server --- .../agent/api/StartupPxeServerCommand.java | 9 + .../PrepareLinMinPxeServerAnswer.java | 14 + .../PrepareLinMinPxeServerCommand.java | 63 ++++ api/src/com/cloud/api/ApiConstants.java | 2 + api/src/com/cloud/host/Host.java | 3 +- .../com/cloud/vm/VirtualMachineProfile.java | 3 +- .../cloud/agent/manager/AgentManagerImpl.java | 6 +- server/src/com/cloud/api/AddPxeServerCmd.java | 103 ++++++ .../cloud/api/response/PxeServerResponse.java | 18 + .../baremetal/LinMinPxeServerManager.java | 5 + .../baremetal/LinMinPxeServerManagerImpl.java | 121 +++++++ .../baremetal/LinMinPxeServerResource.java | 321 ++++++++++++++++++ .../com/cloud/baremetal/PxeServerManager.java | 37 ++ .../cloud/baremetal/PxeServerManagerImpl.java | 70 ++++ .../kvm/discoverer/KvmServerDiscoverer.java | 86 +---- .../cloud/template/TemplateManagerImpl.java | 26 +- .../com/cloud/vm/BareMetalVmManagerImpl.java | 76 ++++- .../src/com/cloud/vm/UserVmManagerImpl.java | 7 + .../src/com/cloud/utils/ssh/SSHCmdHelper.java | 96 ++++++ 19 files changed, 969 insertions(+), 97 deletions(-) create mode 100644 api/src/com/cloud/agent/api/StartupPxeServerCommand.java create mode 100644 api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerAnswer.java create mode 100644 api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerCommand.java create mode 100644 server/src/com/cloud/api/AddPxeServerCmd.java create mode 100644 server/src/com/cloud/api/response/PxeServerResponse.java create mode 100644 server/src/com/cloud/baremetal/LinMinPxeServerManager.java create mode 100644 server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java create mode 100644 server/src/com/cloud/baremetal/LinMinPxeServerResource.java create mode 100644 server/src/com/cloud/baremetal/PxeServerManager.java create mode 100644 server/src/com/cloud/baremetal/PxeServerManagerImpl.java create mode 100644 utils/src/com/cloud/utils/ssh/SSHCmdHelper.java diff --git a/api/src/com/cloud/agent/api/StartupPxeServerCommand.java b/api/src/com/cloud/agent/api/StartupPxeServerCommand.java new file mode 100644 index 00000000000..487f54c463d --- /dev/null +++ b/api/src/com/cloud/agent/api/StartupPxeServerCommand.java @@ -0,0 +1,9 @@ +package com.cloud.agent.api; + +import com.cloud.host.Host; + +public class StartupPxeServerCommand extends StartupCommand { + public StartupPxeServerCommand() { + super(Host.Type.PxeServer); + } +} diff --git a/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerAnswer.java b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerAnswer.java new file mode 100644 index 00000000000..94d1b284667 --- /dev/null +++ b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerAnswer.java @@ -0,0 +1,14 @@ +package com.cloud.agent.api.baremetal; + +import com.cloud.agent.api.Answer; + +public class PrepareLinMinPxeServerAnswer extends Answer { + public PrepareLinMinPxeServerAnswer(PrepareLinMinPxeServerCommand cmd) { + super(cmd, true, "SUCCESS"); + } + + public PrepareLinMinPxeServerAnswer(PrepareLinMinPxeServerCommand cmd, String details) { + super(cmd, false, details); + } + +} diff --git a/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerCommand.java b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerCommand.java new file mode 100644 index 00000000000..33a65377eff --- /dev/null +++ b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerCommand.java @@ -0,0 +1,63 @@ +package com.cloud.agent.api.baremetal; + +import com.cloud.agent.api.Command; + +public class PrepareLinMinPxeServerCommand extends Command { + String ip; + String mac; + String netMask; + String gateway; + String dns; + String template; + String vmName; + String hostName; + + @Override + public boolean executeInSequence() { + return true; + } + + public PrepareLinMinPxeServerCommand(String ip, String mac, String netMask, String gateway, String dns, String template, String vmName, String hostName) { + this.ip = ip; + this.mac = mac; + this.netMask = netMask; + this.gateway = gateway; + this.dns = dns; + this.template = template; + this.vmName = vmName; + this.hostName = hostName; + } + + public String getIp() { + return ip; + } + + public String getMac() { + return mac; + } + + public String getNetMask() { + return netMask; + } + + public String getGateWay() { + return gateway; + } + + public String getDns() { + return dns; + } + + public String getTemplate() { + return template; + } + + public String getVmName() { + return vmName; + } + + public String getHostName() { + return hostName; + } + +} diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 65477ce9967..02605c7a4bd 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -194,5 +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 PXE_SERVER_TYPE = "pxeservertype"; + } diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index ef5baf1cb53..d620e631b7f 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -32,7 +32,8 @@ public interface Host { SecondaryStorage(false), ConsoleProxy(true), ExternalFirewall(false), - ExternalLoadBalancer(false); + ExternalLoadBalancer(false), + PxeServer(false); boolean _virtual; private Type(boolean virtual) { diff --git a/api/src/com/cloud/vm/VirtualMachineProfile.java b/api/src/com/cloud/vm/VirtualMachineProfile.java index d3cece441ae..0d2f88b15ad 100644 --- a/api/src/com/cloud/vm/VirtualMachineProfile.java +++ b/api/src/com/cloud/vm/VirtualMachineProfile.java @@ -47,7 +47,8 @@ public interface VirtualMachineProfile { public static final Param VmPassword = new Param("VmPassword"); public static final Param ControlNic = new Param("ControlNic"); public static final Param RestartNetwork = new Param("RestartNetwork"); - + public static final Param PxeSeverType = new Param("PxeSeverType"); + private String name; public Param(String name) { diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index c95e5e375f8..237088283e7 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -63,6 +63,7 @@ import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupExternalFirewallCommand; import com.cloud.agent.api.StartupExternalLoadBalancerCommand; import com.cloud.agent.api.StartupProxyCommand; +import com.cloud.agent.api.StartupPxeServerCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.UnsupportedAnswer; @@ -2363,6 +2364,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, type = Host.Type.ExternalFirewall; } else if (startup instanceof StartupExternalLoadBalancerCommand) { type = Host.Type.ExternalLoadBalancer; + } else if (startup instanceof StartupPxeServerCommand) { + type = Host.Type.PxeServer; } else { assert false : "Did someone add a new Startup command?"; } @@ -2617,7 +2620,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, if (p == null) { if (type != Host.Type.SecondaryStorage && type != Host.Type.ExternalFirewall - && type != Host.Type.ExternalLoadBalancer) { + && type != Host.Type.ExternalLoadBalancer + && type != Host.Type.PxeServer) { /* * s_logger.info("Unable to find the pod so we are creating one." diff --git a/server/src/com/cloud/api/AddPxeServerCmd.java b/server/src/com/cloud/api/AddPxeServerCmd.java new file mode 100644 index 00000000000..7778bca87ce --- /dev/null +++ b/server/src/com/cloud/api/AddPxeServerCmd.java @@ -0,0 +1,103 @@ +package com.cloud.api; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.ServerApiException; +import com.cloud.api.response.PxeServerResponse; +import com.cloud.baremetal.LinMinPxeServerManager; +import com.cloud.baremetal.PxeServerManager; +import com.cloud.baremetal.PxeServerManager.PxeServerType; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.cloud.server.ManagementService; +import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.exception.CloudRuntimeException; + +@Implementation(description="Adds a PXE server appliance", responseObject = PxeServerResponse.class) +public class AddPxeServerCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(AddPxeServerCmd.class.getName()); + private static final String s_name = "addpxeserverresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external firewall appliance.") + private Long zoneId; + + @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the PXE server appliance.") + private String url; + + @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Username of PXE server appliance.") + private String username; + + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Password of the PXE server appliance.") + private String password; + + @Parameter(name=ApiConstants.PXE_SERVER_TYPE, type=CommandType.STRING, required = true, description="Type of PXE server. Current values are LinMin, DMCD") + private String type; + + /////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getZoneId() { + return zoneId; + } + + public String getUrl() { + return url; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getType() { + return type; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, + ResourceAllocationException { + try { + PxeServerManager pxeServerMgr; + ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); + if (getType().equalsIgnoreCase(PxeServerType.LinMin.getName())) { + pxeServerMgr = locator.getManager(LinMinPxeServerManager.class); + } else { + throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unsupport PXE server type " + getType()); + } + Host pxeServer = pxeServerMgr.addPxeServer(this); + PxeServerResponse response = pxeServerMgr.getApiResponse(pxeServer); + response.setObjectName("pxeserver"); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } catch (InvalidParameterValueException ipve) { + throw new ServerApiException(BaseCmd.PARAM_ERROR, ipve.getMessage()); + } catch (CloudRuntimeException cre) { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, cre.getMessage()); + } + } +} diff --git a/server/src/com/cloud/api/response/PxeServerResponse.java b/server/src/com/cloud/api/response/PxeServerResponse.java new file mode 100644 index 00000000000..f2f167dce45 --- /dev/null +++ b/server/src/com/cloud/api/response/PxeServerResponse.java @@ -0,0 +1,18 @@ +package com.cloud.api.response; + +import com.cloud.api.ApiConstants; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class PxeServerResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the PXE server") + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManager.java b/server/src/com/cloud/baremetal/LinMinPxeServerManager.java new file mode 100644 index 00000000000..745c89dc594 --- /dev/null +++ b/server/src/com/cloud/baremetal/LinMinPxeServerManager.java @@ -0,0 +1,5 @@ +package com.cloud.baremetal; + +public interface LinMinPxeServerManager extends PxeServerManager { + +} diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java new file mode 100644 index 00000000000..73db98ef369 --- /dev/null +++ b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java @@ -0,0 +1,121 @@ +package com.cloud.baremetal; + +import java.net.URI; +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.AgentManager; +import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerAnswer; +import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; +import com.cloud.api.AddPxeServerCmd; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.resource.ServerResource; +import com.cloud.utils.component.Inject; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachineProfile; + +@Local(value = {LinMinPxeServerManager.class}) +public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements LinMinPxeServerManager { + private static final org.apache.log4j.Logger s_logger = Logger.getLogger(LinMinPxeServerManagerImpl.class); + @Inject DataCenterDao _dcDao; + @Inject HostDao _hostDao; + @Inject AgentManager _agentMgr; + + @Override + public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { + long zoneId = cmd.getZoneId(); + + DataCenterVO zone = _dcDao.findById(zoneId); + String zoneName; + if (zone == null) { + throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); + } else { + zoneName = zone.getName(); + } + + List pxeServers = _hostDao.listByTypeDataCenter(Host.Type.PxeServer, zoneId); + if (pxeServers.size() != 0) { + throw new InvalidParameterValueException("Already had a PXE server in zone: " + zoneName); + } + + URI uri; + try { + uri = new URI(cmd.getUrl()); + } catch (Exception e) { + s_logger.debug(e); + throw new InvalidParameterValueException(e.getMessage()); + } + + String ipAddress = uri.getHost(); + String username = cmd.getUsername(); + String password = cmd.getPassword(); + String guid = getPxeServerGuid(Long.toString(zoneId), PxeServerType.LinMin.getName(), ipAddress); + Map params = new HashMap(); + params.put("zone", Long.toString(zoneId)); + params.put("ip", ipAddress); + params.put("username", username); + params.put("password", password); + params.put("guid", guid); + + ServerResource resource = null; + try { + if (cmd.getType().equalsIgnoreCase(PxeServerType.LinMin.getName())) { + resource = new LinMinPxeServerResource(); + resource.configure("LinMin PXE resource", params); + } + } catch (Exception e) { + s_logger.debug(e); + throw new CloudRuntimeException(e.getMessage()); + } + + Host pxeServer = _agentMgr.addHost(zoneId, resource, Host.Type.PxeServer, params); + if (pxeServer == null) { + throw new CloudRuntimeException("Cannot add PXE server as a host"); + } + + return pxeServer; + } + + @Override + public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId) { + List nics = profile.getNics(); + if (nics.size() == 0) { + throw new CloudRuntimeException("Cannot do PXE start without nic"); + } + + NicProfile pxeNic = nics.get(0); + String mac = pxeNic.getMacAddress(); + String ip = pxeNic.getIp4Address(); + String gateway = pxeNic.getGateway(); + String mask = pxeNic.getNetmask(); + String dns = pxeNic.getDns1(); + if (dns == null) { + dns = pxeNic.getDns2(); + } + + try { + String linMinTpl = profile.getTemplate().getUrl(); + assert linMinTpl != null : "How can a null template get here!!!"; + PrepareLinMinPxeServerCommand cmd = new PrepareLinMinPxeServerCommand(ip, mac, mask, gateway, dns, linMinTpl, + profile.getVirtualMachine().getName(), dest.getHost().getName()); + PrepareLinMinPxeServerAnswer ans = (PrepareLinMinPxeServerAnswer) _agentMgr.send(pxeServerId, cmd); + return ans.getResult(); + } catch (Exception e) { + s_logger.warn("Cannot prepare PXE server", e); + return false; + } + } +} diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java new file mode 100644 index 00000000000..99b53bd5954 --- /dev/null +++ b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java @@ -0,0 +1,321 @@ +package com.cloud.baremetal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Map; + +import javax.naming.ConfigurationException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import com.cloud.agent.IAgentControl; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.ReadyAnswer; +import com.cloud.agent.api.ReadyCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupPxeServerCommand; +import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerAnswer; +import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Host.Type; +import com.cloud.resource.ServerResource; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.ssh.SSHCmdHelper; + +public class LinMinPxeServerResource implements ServerResource { + private static final Logger s_logger = Logger.getLogger(LinMinPxeServerResource.class); + String _name; + String _guid; + String _username; + String _password; + String _ip; + String _zoneId; + + class XmlReturn { + NodeList nList; + public XmlReturn(InputSource s, String tagName) { + try { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(s); + doc.getDocumentElement().normalize(); + nList = doc.getElementsByTagName(tagName); + } catch (Exception e) { + s_logger.debug("The XML file:"); + s_logger.debug(s.toString()); + s_logger.debug("Cannot parse XMl file", e); + nList = null; + } + } + + public String getValue(String tag) { + if (nList == null || nList.getLength() == 0) { + throw new InvalidParameterValueException("invalid XML file"); + } + + Element e = (Element)nList.item(0); + NodeList nlList= e.getElementsByTagName(tag).item(0).getChildNodes(); + Node nValue = (Node)nlList.item(0); + return nValue.getNodeValue(); + } + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + _guid = (String)params.get("guid"); + _ip = (String)params.get("ip"); + _username = (String)params.get("username"); + _password = (String)params.get("password"); + _zoneId = (String)params.get("zone"); + + if (_guid == null) { + throw new ConfigurationException("No Guid specified"); + } + + if (_zoneId == null) { + throw new ConfigurationException("No Zone specified"); + } + + if (_ip == null) { + throw new ConfigurationException("No IP specified"); + } + + if (_username == null) { + throw new ConfigurationException("No username specified"); + } + + if (_password == null) { + throw new ConfigurationException("No password specified"); + } + + com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22); + + s_logger.debug(String.format("Trying to connect to LinMin PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); + try { + sshConnection.connect(null, 60000, 60000); + if (!sshConnection.authenticateWithPassword(_username, _password)) { + s_logger.debug("SSH Failed to authenticate"); + throw new ConfigurationException(String.format("Cannot connect to LinMin PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, + _password)); + } + + if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "[ -d '/home/tftpboot' ] && [ -d '/usr/local/linmin' ]")) { + throw new ConfigurationException("Cannot find LinMin directory /home/tftpboot, /usr/local/linmin on PXE server"); + } + + return true; + } catch (Exception e) { + throw new ConfigurationException(e.getMessage()); + } finally { + if (sshConnection != null) { + sshConnection.close(); + } + } + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + @Override + public Type getType() { + return Type.PxeServer; + } + + @Override + public StartupCommand[] initialize() { + StartupPxeServerCommand cmd = new StartupPxeServerCommand(); + cmd.setName(_name); + cmd.setDataCenter(_zoneId); + cmd.setPod(""); + cmd.setPrivateIpAddress(_ip); + cmd.setStorageIpAddress(""); + cmd.setVersion(""); + cmd.setGuid(_guid); + return new StartupCommand[]{cmd}; + } + + @Override + public PingCommand getCurrentStatus(long id) { + // TODO Auto-generated method stub + return null; + } + + protected ReadyAnswer execute(ReadyCommand cmd) { + s_logger.debug("LinMin resource " + _name + " is ready"); + return new ReadyAnswer(cmd); + } + + private InputSource httpCall(String urlStr) { + try { + s_logger.debug("Execute http call " + urlStr); + URL url = new URL(urlStr); + URLConnection conn = url.openConnection(); + conn.setReadTimeout(30000); + BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); + StringBuffer xmlStuff = new StringBuffer(); + String line; + while ((line = in.readLine()) != null) { + xmlStuff.append(line); + } + StringReader statsReader = new StringReader(xmlStuff.toString()); + InputSource statsSource = new InputSource(statsReader); + s_logger.debug("Http call retrun:"); + s_logger.debug(xmlStuff.toString()); + return statsSource; + } catch (MalformedURLException e) { + throw new CloudRuntimeException("URL is malformed " + urlStr, e); + } catch (IOException e) { + s_logger.warn("can not do http call", e); + return null; + }catch (Exception e) { + s_logger.warn("Cannot do http call " + urlStr, e); + throw new CloudRuntimeException(e.getStackTrace().toString()); + } + } + + + protected PrepareLinMinPxeServerAnswer execute(PrepareLinMinPxeServerCommand cmd) { + String apiUserName = "root"; + String apiPassword = "password"; + String apid = "2ad644fb479871a0f5543dd6d29fe9ed"; + StringBuffer askApid = new StringBuffer(); + + askApid.append("http://"); + askApid.append(_ip); + askApid.append("/tftpboot/www/lbmp-API.php?actiontype=provision&apid="); + askApid.append(apid); + askApid.append("&auth_user="); + askApid.append(apiUserName); + askApid.append("&auth_user_pw="); + askApid.append(apiPassword); + askApid.append("&rtn_format=XML&action=authorize"); + InputSource s = httpCall(askApid.toString()); + if (s == null) { + return new PrepareLinMinPxeServerAnswer(cmd, "Http call failed"); + } + + try { + XmlReturn r = new XmlReturn(s, "LinMinBareMetalAPI"); + String res = r.getValue("actionResultsMsg"); + s_logger.debug(s.toString()); + if (!res.startsWith("Successful")) { + return new PrepareLinMinPxeServerAnswer(cmd, "Acquire APID failed"); + } + + String apid5 = r.getValue("apid"); + if (apid5 == null) { + return new PrepareLinMinPxeServerAnswer(cmd, "Cannot get 5 minutes APID " + apid5); + } + + StringBuffer addRole = new StringBuffer(); + addRole.append("http://"); + addRole.append(_ip); + addRole.append("/tftpboot/www/lbmp-API.php?actiontype=provision&user_supplied_id="); + addRole.append(cmd.getVmName()); + addRole.append("&mac_address="); + addRole.append(cmd.getMac().replaceAll(":", "%3A")); + addRole.append("&apid="); + addRole.append(apid5); + addRole.append("&control_file_template="); + addRole.append(cmd.getTemplate().replace(' ', '+')); + addRole.append("&node_name="); + addRole.append(cmd.getHostName()); + addRole.append("&node_domain="); + addRole.append(cmd.getHostName()); + addRole.append("&node_password=password"); + addRole.append("&node_time_zone=Etc%2FGMT-8"); + if (cmd.getIp() != null) { + addRole.append("&node_ip_address="); + addRole.append(cmd.getIp()); + } + if (cmd.getNetMask() != null) { + addRole.append("&node_subnet_mask="); + addRole.append(cmd.getNetMask()); + } + if (cmd.getDns() != null) { + addRole.append("&node_nameserver="); + addRole.append(cmd.getDns()); + } + if (cmd.getGateWay() != null) { + addRole.append("&node_default_gateway="); + addRole.append(cmd.getGateWay()); + } + addRole.append("&enable_provisioning_flag=nextbootonly&rtn_format=XML&action=add"); + + s = httpCall(addRole.toString()); + if (s == null) { + return new PrepareLinMinPxeServerAnswer(cmd, "Http call failed"); + } + r = new XmlReturn(s, "LinMinBareMetalAPI"); + res = r.getValue("actionResultsMsg"); + s_logger.debug(s.toString()); + if (!res.startsWith("Successful")) { + return new PrepareLinMinPxeServerAnswer(cmd, "Add LinMin role failed"); + } + } catch (Exception e) { + s_logger.warn("Cannot parse result from Lin Min server", e); + return new PrepareLinMinPxeServerAnswer(cmd, e.getMessage()); + } + + s_logger.debug("Prepare LinMin PXE server successfully"); + return new PrepareLinMinPxeServerAnswer(cmd); + } + + @Override + public Answer executeRequest(Command cmd) { + if (cmd instanceof ReadyCommand) { + return execute((ReadyCommand) cmd); + } else if (cmd instanceof PrepareLinMinPxeServerCommand) { + return execute((PrepareLinMinPxeServerCommand)cmd); + } else { + return Answer.createUnsupportedCommandAnswer(cmd); + } + } + + @Override + public void disconnected() { + // TODO Auto-generated method stub + + } + + @Override + public IAgentControl getAgentControl() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setAgentControl(IAgentControl agentControl) { + // TODO Auto-generated method stub + + } + +} diff --git a/server/src/com/cloud/baremetal/PxeServerManager.java b/server/src/com/cloud/baremetal/PxeServerManager.java new file mode 100644 index 00000000000..f1ac51aa1fb --- /dev/null +++ b/server/src/com/cloud/baremetal/PxeServerManager.java @@ -0,0 +1,37 @@ +package com.cloud.baremetal; + +import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; +import com.cloud.api.AddPxeServerCmd; +import com.cloud.api.response.PxeServerResponse; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Host; +import com.cloud.utils.component.Manager; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachineProfile; + +public interface PxeServerManager extends Manager { + public static class PxeServerType { + private String _name; + + public static final PxeServerType LinMin = new PxeServerType("LinMin"); + public static final PxeServerType DMCD = new PxeServerType("DMCD"); + + public PxeServerType(String name) { + _name = name; + } + + public String getName() { + return _name; + } + + } + + public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException; + + public PxeServerResponse getApiResponse(Host pxeServer); + + public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId); +} diff --git a/server/src/com/cloud/baremetal/PxeServerManagerImpl.java b/server/src/com/cloud/baremetal/PxeServerManagerImpl.java new file mode 100644 index 00000000000..77a20bf4dcd --- /dev/null +++ b/server/src/com/cloud/baremetal/PxeServerManagerImpl.java @@ -0,0 +1,70 @@ +package com.cloud.baremetal; + +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; +import com.cloud.api.AddPxeServerCmd; +import com.cloud.api.response.PxeServerResponse; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Host; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachineProfile; + +@Local(value = {PxeServerManager.class}) +public class PxeServerManagerImpl implements PxeServerManager { + private static final org.apache.log4j.Logger s_logger = Logger.getLogger(PxeServerManagerImpl.class); + protected String _name; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + protected String getPxeServerGuid(String zoneId, String name, String ip) { + return zoneId + "-" + name + "-" + ip; + } + + @Override + public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { + // TODO Auto-generated method stub + return null; + } + + @Override + public PxeServerResponse getApiResponse(Host pxeServer) { + PxeServerResponse response = new PxeServerResponse(); + response.setId(pxeServer.getId()); + return response; + } + + + @Override + public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId) { + return true; + } + +} diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java index 1c4b028929c..b881243b8ca 100644 --- a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java @@ -1,7 +1,5 @@ package com.cloud.hypervisor.kvm.discoverer; -import java.io.IOException; -import java.io.InputStream; import java.net.InetAddress; import java.net.URI; import java.util.HashMap; @@ -38,6 +36,7 @@ import com.cloud.resource.ServerResource; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Inject; import com.cloud.utils.script.Script; +import com.cloud.utils.ssh.SSHCmdHelper; import com.trilead.ssh2.ChannelCondition; import com.trilead.ssh2.SCPClient; import com.trilead.ssh2.Session; @@ -101,85 +100,6 @@ public class KvmServerDiscoverer extends DiscovererBase implements Discoverer, // TODO Auto-generated method stub return false; } - - private static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd) { - s_logger.debug("Executing cmd: " + cmd); - Session sshSession = null; - try { - sshSession = sshConnection.openSession(); - // There is a bug in Trilead library, wait a second before - // starting a shell and executing commands, from http://spci.st.ewi.tudelft.nl/chiron/xref/nl/tudelft/swerl/util/SSHConnection.html - Thread.sleep(1000); - - if (sshSession == null) { - return false; - } - - sshSession.execCommand(cmd); - - InputStream stdout = sshSession.getStdout(); - InputStream stderr = sshSession.getStderr(); - - - byte[] buffer = new byte[8192]; - while (true) { - if (stdout == null || stderr == null) { - return false; - } - - if ((stdout.available() == 0) && (stderr.available() == 0)) { - int conditions = sshSession.waitForCondition( - ChannelCondition.STDOUT_DATA - | ChannelCondition.STDERR_DATA - | ChannelCondition.EOF, 120000); - - if ((conditions & ChannelCondition.TIMEOUT) != 0) { - s_logger.info("Timeout while waiting for data from peer."); - break; - } - - if ((conditions & ChannelCondition.EOF) != 0) { - if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) { - break; - } - } - } - - while (stdout.available() > 0) { - stdout.read(buffer); - } - - while (stderr.available() > 0) { - stderr.read(buffer); - } - } - - Thread.sleep(1000); - if (sshSession.getExitStatus() != 0) { - return false; - } - - return true; - } catch (IOException e) { - s_logger.debug("Executing cmd: " + cmd + " failed, due to: " + e.toString()); - return false; - } catch (InterruptedException e) { - return false; - } catch (Exception e) { - return false; - } finally { - if (sshSession != null) - sshSession.close(); - } - } - - private static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd, int nTimes) { - for (int i = 0; i < nTimes; i ++) { - if (sshExecuteCmd(sshConnection, cmd)) - return true; - } - return false; - } @Override public Map> find(long dcId, @@ -222,7 +142,7 @@ public class KvmServerDiscoverer extends DiscovererBase implements Discoverer, return null; } - if (!sshExecuteCmd(sshConnection, "lsmod|grep kvm >& /dev/null", 3)) { + if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "lsmod|grep kvm >& /dev/null", 3)) { s_logger.debug("It's not a KVM enabled machine"); return null; } @@ -241,7 +161,7 @@ public class KvmServerDiscoverer extends DiscovererBase implements Discoverer, parameters += " -N " + _kvmPrivateNic; } - sshExecuteCmd(sshConnection, "/usr/bin/setup_agent.sh " + parameters + " 1>&2", 3); + SSHCmdHelper.sshExecuteCmd(sshConnection, "/usr/bin/setup_agent.sh " + parameters + " 1>&2", 3); KvmDummyResourceBase kvmResource = new KvmDummyResourceBase(); Map params = new HashMap(); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 927d4bb2e6f..9a2c5e5eb02 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -380,13 +380,18 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe if (imgfmt == null) { throw new IllegalArgumentException("Image format is incorrect " + format + ". Supported formats are " + EnumUtils.listValues(ImageFormat.values())); } - - URI uri = new URI(url); - if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file") && !uri.getScheme().equalsIgnoreCase("baremetal"))) { - throw new IllegalArgumentException("Unsupported scheme for url: " + url); - } - - if (!uri.getScheme().equalsIgnoreCase("baremetal")) { + + String uriStr; + if (url.startsWith("baremetal://")) { + uriStr = url.substring("baremetal://".length()); + } else { + URI uri = new URI(url); + if ((uri.getScheme() == null) + || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme() + .equalsIgnoreCase("file"))) { + throw new IllegalArgumentException("Unsupported scheme for url: " + url); + } + int port = uri.getPort(); if (!(port == 80 || port == 443 || port == -1)) { throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); @@ -403,6 +408,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } catch (UnknownHostException uhe) { throw new IllegalArgumentException("Unable to resolve " + host); } + uriStr = uri.toString(); } // Check that the resource limit for templates/ISOs won't be exceeded @@ -431,13 +437,13 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } } - return create(userId, accountId, zoneId, name, displayText, isPublic, featured, isExtractable, imgfmt, diskType, uri, chksum, requiresHvm, bits, enablePassword, guestOSId, bootable, hypervisorType); + return create(userId, accountId, zoneId, name, displayText, isPublic, featured, isExtractable, imgfmt, diskType, uriStr, chksum, requiresHvm, bits, enablePassword, guestOSId, bootable, hypervisorType); } catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid URL " + url); } } - private VMTemplateVO create(long userId, long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, boolean isExtractable, ImageFormat format, TemplateType type, URI url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { + private VMTemplateVO create(long userId, long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, boolean isExtractable, ImageFormat format, TemplateType type, String url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { Long id = _tmpltDao.getNextInSequence(Long.class, "id"); AccountVO account = _accountDao.findById(accountId); @@ -445,7 +451,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new IllegalArgumentException("Only admins can create templates in all zones"); } - VMTemplateVO template = new VMTemplateVO(id, name, format, isPublic, featured, isExtractable, type, url.toString(), requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, hyperType); + VMTemplateVO template = new VMTemplateVO(id, name, format, isPublic, featured, isExtractable, type, url, requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, hyperType); if (zoneId == null) { List dcs = _dcDao.listAllIncludingRemoved(); diff --git a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java index 59a71cb7caa..c438bad73ff 100644 --- a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java @@ -1,6 +1,12 @@ package com.cloud.vm; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; @@ -10,12 +16,16 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; import com.cloud.agent.manager.Commands; import com.cloud.api.commands.AttachVolumeCmd; import com.cloud.api.commands.CreateTemplateCmd; import com.cloud.api.commands.DeployVMCmd; import com.cloud.api.commands.DetachVolumeCmd; import com.cloud.api.commands.UpgradeVMCmd; +import com.cloud.baremetal.LinMinPxeServerManager; +import com.cloud.baremetal.PxeServerManager; +import com.cloud.baremetal.PxeServerManager.PxeServerType; import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenterVO; @@ -32,28 +42,36 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network; import com.cloud.network.NetworkVO; +import com.cloud.network.IpAddrAllocator.IpAddr; import com.cloud.network.Networks.TrafficType; +import com.cloud.server.ManagementService; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.Storage; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.Storage.TemplateType; import com.cloud.user.Account; +import com.cloud.user.AccountVO; import com.cloud.user.SSHKeyPair; import com.cloud.user.UserContext; +import com.cloud.user.UserVO; import com.cloud.uservm.UserVm; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Manager; import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.crypt.RSAHelper; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.VirtualMachineProfile.Param; @Local(value={BareMetalVmManager.class, BareMetalVmService.class}) public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMetalVmManager, BareMetalVmService, Manager { @@ -286,7 +304,30 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet } public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { - return super.startVirtualMachine(cmd); + long vmId = cmd.getEntityId(); + UserVmVO vm = _vmDao.findById(vmId); + _vmDao.loadDetails(vm); + + List servers = _hostDao.listBy(Host.Type.PxeServer, vm.getDataCenterId()); + if (servers.size() == 0) { + throw new CloudRuntimeException("Cannot find PXE server, please make sure there is one PXE server per zone"); + } + HostVO pxeServer = servers.get(0); + + VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); + if (template == null || template.getFormat() != Storage.ImageFormat.BAREMETAL) { + throw new InvalidParameterValueException("Invalid template with id = " + vm.getTemplateId()); + } + + Map params = new HashMap(); + //TODO: have to ugly harding code here + if (pxeServer.getResource().equalsIgnoreCase("com.cloud.baremetal.LinMinPxeServerResource")) { + params.put(Param.PxeSeverType, PxeServerType.LinMin); + } else { + throw new CloudRuntimeException("Unkown PXE server resource " + pxeServer.getResource()); + } + + return startVirtualMachine(cmd, params); } @Override @@ -333,6 +374,39 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet throw new PermissionDeniedException("The owner of " + vm + " either does not exist or is disabled: " + vm.getAccountId()); } + if (profile.getTemplate() == null) { + s_logger.debug("This is a normal IPMI start, skip prepartion of PXE server"); + return true; + } + + s_logger.debug("This is a PXE start, prepare PXE server first"); + PxeServerType pxeType = (PxeServerType) profile.getParameter(Param.PxeSeverType); + if (pxeType == null) { + throw new CloudRuntimeException("No PXE type specified"); + } + + PxeServerManager pxeMgr = null; + ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); + if (pxeType == PxeServerType.LinMin) { + pxeMgr = locator.getManager(LinMinPxeServerManager.class); + } else { + throw new CloudRuntimeException("Unsupport PXE type " + pxeType.toString()); + } + + if (pxeMgr == null) { + throw new CloudRuntimeException("No PXE manager find for type " + pxeType.toString()); + } + + List servers = _hostDao.listBy(Host.Type.PxeServer, vm.getDataCenterId()); + if (servers.size() == 0) { + throw new CloudRuntimeException("Cannot find PXE server, please make sure there is one PXE server per zone"); + } + HostVO pxeServer = servers.get(0); + + if (!pxeMgr.prepare(profile, dest, context, pxeServer.getId())) { + throw new CloudRuntimeException("Pepare PXE server failed"); + } + return true; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 0104af99c2c..eb038e3257d 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2106,6 +2106,10 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Override @ActionEvent (eventType=EventTypes.EVENT_VM_CREATE, eventDescription="starting Vm", async=true) public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { + return startVirtualMachine(cmd, null); + } + + protected UserVm startVirtualMachine(DeployVMCmd cmd, Map additonalParams) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { long vmId = cmd.getEntityId(); UserVmVO vm = _vmDao.findById(vmId); _vmDao.loadDetails(vm); @@ -2142,6 +2146,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager try { Map params = new HashMap(); + if (additonalParams != null) { + params.putAll(additonalParams); + } params.put(VirtualMachineProfile.Param.VmPassword, password); vm = _itMgr.start(vm, params, caller, owner); } finally { diff --git a/utils/src/com/cloud/utils/ssh/SSHCmdHelper.java b/utils/src/com/cloud/utils/ssh/SSHCmdHelper.java new file mode 100644 index 00000000000..2798c2d754e --- /dev/null +++ b/utils/src/com/cloud/utils/ssh/SSHCmdHelper.java @@ -0,0 +1,96 @@ +package com.cloud.utils.ssh; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.log4j.Logger; + +import com.trilead.ssh2.ChannelCondition; +import com.trilead.ssh2.Session; + +public class SSHCmdHelper { + private static final Logger s_logger = Logger.getLogger(SSHCmdHelper.class); + + public static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd, int nTimes) { + for (int i = 0; i < nTimes; i ++) { + if (sshExecuteCmdOneShot(sshConnection, cmd)) + return true; + } + return false; + } + + public static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd) { + return sshExecuteCmd(sshConnection, cmd, 3); + } + + public static boolean sshExecuteCmdOneShot(com.trilead.ssh2.Connection sshConnection, String cmd) { + s_logger.debug("Executing cmd: " + cmd); + Session sshSession = null; + try { + sshSession = sshConnection.openSession(); + // There is a bug in Trilead library, wait a second before + // starting a shell and executing commands, from http://spci.st.ewi.tudelft.nl/chiron/xref/nl/tudelft/swerl/util/SSHConnection.html + Thread.sleep(1000); + + if (sshSession == null) { + return false; + } + + sshSession.execCommand(cmd); + + InputStream stdout = sshSession.getStdout(); + InputStream stderr = sshSession.getStderr(); + + + byte[] buffer = new byte[8192]; + while (true) { + if (stdout == null || stderr == null) { + return false; + } + + if ((stdout.available() == 0) && (stderr.available() == 0)) { + int conditions = sshSession.waitForCondition( + ChannelCondition.STDOUT_DATA + | ChannelCondition.STDERR_DATA + | ChannelCondition.EOF, 120000); + + if ((conditions & ChannelCondition.TIMEOUT) != 0) { + s_logger.info("Timeout while waiting for data from peer."); + break; + } + + if ((conditions & ChannelCondition.EOF) != 0) { + if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) { + break; + } + } + } + + while (stdout.available() > 0) { + stdout.read(buffer); + } + + while (stderr.available() > 0) { + stderr.read(buffer); + } + } + + Thread.sleep(1000); + if (sshSession.getExitStatus() != 0) { + return false; + } + + return true; + } catch (IOException e) { + s_logger.debug("Executing cmd: " + cmd + " failed, due to: " + e.toString()); + return false; + } catch (InterruptedException e) { + return false; + } catch (Exception e) { + return false; + } finally { + if (sshSession != null) + sshSession.close(); + } + } +} From cd676f481d0d3e2847a85edb4ab7ca88ad59b0bf Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 25 Feb 2011 21:08:13 -0800 Subject: [PATCH 06/11] Bug 8208 - bare metal provisioning Successfully add start entry into LinMin PXE server --- client/tomcatconf/commands.properties.in | 5 ++- scripts/util/ipmi.py | 39 ++++++++++++++++++- .../baremetal/LinMinPxeServerResource.java | 7 +++- .../src/com/cloud/network/NetworkManager.java | 1 + .../com/cloud/vm/BareMetalVmManagerImpl.java | 2 + 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 9b12f467c82..8d330d45948 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -251,4 +251,7 @@ restartNetwork=com.cloud.api.commands.RestartNetworkCmd;15 registerSSHKeyPair=com.cloud.api.commands.RegisterSSHKeyPairCmd;15 createSSHKeyPair=com.cloud.api.commands.CreateSSHKeyPairCmd;15 deleteSSHKeyPair=com.cloud.api.commands.DeleteSSHKeyPairCmd;15 -listSSHKeyPairs=com.cloud.api.commands.ListSSHKeyPairsCmd;15 +listSSHKeyPairs=com.cloud.api.commands.ListSSHKeyPairsCmd;15 + +### PXE server commands +AddPxeServer=com.cloud.api.AddPxeServerCmd;1 diff --git a/scripts/util/ipmi.py b/scripts/util/ipmi.py index 9fc4674a155..fa819c61fd1 100644 --- a/scripts/util/ipmi.py +++ b/scripts/util/ipmi.py @@ -80,7 +80,44 @@ def ping(args): else: return 0 -call_table = {"ping":ping} +def boot_dev(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + dev = args.get("dev") + + if hostname == None: + print "No hostname" + return 1 + + if dev == None: + print "No boot device specified" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "bootdev", dev) + if o.ret: + print o.stderr + return 1 + else: + return 0 + +def reboot(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + + if hostname == None: + print "No hostname" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "reset") + if o.ret: + print o.stderr + return 1 + else: + return 0 + +call_table = {"ping":ping, "boot_dev":boot_dev, "reboot":reboot} def dispatch(args): cmd = args[1] params = args[2:] diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java index 99b53bd5954..401ec2e04b4 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java @@ -8,6 +8,7 @@ import java.io.StringReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; +import java.util.HashMap; import java.util.Map; import javax.naming.ConfigurationException; @@ -25,6 +26,7 @@ import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; @@ -36,6 +38,7 @@ import com.cloud.host.Host.Type; import com.cloud.resource.ServerResource; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.ssh.SSHCmdHelper; +import com.cloud.vm.VirtualMachine.State; public class LinMinPxeServerResource implements ServerResource { private static final Logger s_logger = Logger.getLogger(LinMinPxeServerResource.class); @@ -164,8 +167,8 @@ public class LinMinPxeServerResource implements ServerResource { @Override public PingCommand getCurrentStatus(long id) { - // TODO Auto-generated method stub - return null; + //TODO: check server + return new PingRoutingCommand(getType(), id, new HashMap()); } protected ReadyAnswer execute(ReadyCommand cmd) { diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index a11c9865479..c345a5aca28 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -42,6 +42,7 @@ import com.cloud.user.AccountVO; import com.cloud.utils.Pair; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; diff --git a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java index c438bad73ff..34521df33db 100644 --- a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java @@ -407,6 +407,8 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet throw new CloudRuntimeException("Pepare PXE server failed"); } + profile.addBootArgs("PxeBoot"); + return true; } From 35b7c26689c299a6edaae85425958ca0a03de1b2 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 1 Mar 2011 11:40:40 -0800 Subject: [PATCH 07/11] Bug 8208 - bare metal provisioning able to start, stop, reboot, destroy VM --- .../com/cloud/api/commands/DestroyVMCmd.java | 9 +++++++- .../com/cloud/api/commands/RebootVMCmd.java | 9 +++++++- .../com/cloud/api/commands/StartVMCmd.java | 9 +++++++- api/src/com/cloud/api/commands/StopVMCmd.java | 10 +++++++- api/src/com/cloud/vm/UserVmService.java | 3 +++ scripts/util/ipmi.py | 20 +++++++++++++++- server/src/com/cloud/api/AddPxeServerCmd.java | 7 ++++++ .../baremetal/LinMinPxeServerManagerImpl.java | 12 +++++----- .../baremetal/LinMinPxeServerResource.java | 8 ++++++- .../com/cloud/vm/BareMetalVmManagerImpl.java | 23 +++++++++++++------ .../src/com/cloud/vm/UserVmManagerImpl.java | 10 ++++++++ .../cloud/vm/VirtualMachineManagerImpl.java | 6 +++-- utils/src/com/cloud/utils/script/Script.java | 6 +++++ 13 files changed, 111 insertions(+), 21 deletions(-) diff --git a/api/src/com/cloud/api/commands/DestroyVMCmd.java b/api/src/com/cloud/api/commands/DestroyVMCmd.java index 3fd4bc1cc07..3a44ed19857 100644 --- a/api/src/com/cloud/api/commands/DestroyVMCmd.java +++ b/api/src/com/cloud/api/commands/DestroyVMCmd.java @@ -30,6 +30,7 @@ import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -95,7 +96,13 @@ public class DestroyVMCmd extends BaseAsyncCmd { @Override public void execute() throws ResourceUnavailableException, ConcurrentOperationException{ UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.destroyVm(this); + UserVm result; + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.destroyVm(this); + } else { + result = _userVmService.destroyVm(this); + } + if (result != null) { UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName("virtualmachine"); diff --git a/api/src/com/cloud/api/commands/RebootVMCmd.java b/api/src/com/cloud/api/commands/RebootVMCmd.java index e087acd5d37..dc1669fd80d 100644 --- a/api/src/com/cloud/api/commands/RebootVMCmd.java +++ b/api/src/com/cloud/api/commands/RebootVMCmd.java @@ -30,6 +30,7 @@ import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -94,7 +95,13 @@ public class RebootVMCmd extends BaseAsyncCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException{ UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.rebootVirtualMachine(this); + UserVm result; + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.rebootVirtualMachine(this); + } else { + result = _userVmService.rebootVirtualMachine(this); + } + if (result !=null){ UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/StartVMCmd.java b/api/src/com/cloud/api/commands/StartVMCmd.java index 640c75b9bce..389de61828f 100644 --- a/api/src/com/cloud/api/commands/StartVMCmd.java +++ b/api/src/com/cloud/api/commands/StartVMCmd.java @@ -33,6 +33,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -104,7 +105,13 @@ public class StartVMCmd extends BaseAsyncCmd { public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException{ try { UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.startVirtualMachine(this); + UserVm result; + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.startVirtualMachine(this); + } else { + result = _userVmService.startVirtualMachine(this); + } + if (result != null){ UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/StopVMCmd.java b/api/src/com/cloud/api/commands/StopVMCmd.java index 4162bd91e66..bdef118bd8c 100644 --- a/api/src/com/cloud/api/commands/StopVMCmd.java +++ b/api/src/com/cloud/api/commands/StopVMCmd.java @@ -29,6 +29,7 @@ import com.cloud.api.response.UserVmResponse; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -107,7 +108,14 @@ public class StopVMCmd extends BaseAsyncCmd { @Override public void execute() throws ServerApiException, ConcurrentOperationException{ UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.stopVirtualMachine(getId(), isForced()); + UserVm result; + + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.stopVirtualMachine(getId(), isForced()); + } else { + result = _userVmService.stopVirtualMachine(getId(), isForced()); + } + if (result != null) { UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index 643d63761b9..8605c3c9747 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -42,6 +42,7 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Volume; import com.cloud.template.VirtualMachineTemplate; import com.cloud.uservm.UserVm; @@ -170,4 +171,6 @@ public interface UserVmService { * @return List of UserVMs. */ List searchForUserVMs(ListVMsCmd cmd); + + HypervisorType getHypervisorTypeOfUserVM(long vmid); } diff --git a/scripts/util/ipmi.py b/scripts/util/ipmi.py index fa819c61fd1..01258b3baec 100644 --- a/scripts/util/ipmi.py +++ b/scripts/util/ipmi.py @@ -78,6 +78,7 @@ def ping(args): print o.stderr return 1 else: + print o.stdout return 0 def boot_dev(args): @@ -117,7 +118,24 @@ def reboot(args): else: return 0 -call_table = {"ping":ping, "boot_dev":boot_dev, "reboot":reboot} +def power(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + action = args.get("action") + + if hostname == None: + print "No hostname" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "power", action) + if o.ret: + print o.stderr + return 1 + else: + return 0 + +call_table = {"ping":ping, "boot_dev":boot_dev, "reboot":reboot, "power":power} def dispatch(args): cmd = args[1] params = args[2:] diff --git a/server/src/com/cloud/api/AddPxeServerCmd.java b/server/src/com/cloud/api/AddPxeServerCmd.java index 7778bca87ce..f0ec9aefee6 100644 --- a/server/src/com/cloud/api/AddPxeServerCmd.java +++ b/server/src/com/cloud/api/AddPxeServerCmd.java @@ -33,6 +33,9 @@ public class AddPxeServerCmd extends BaseCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external firewall appliance.") private Long zoneId; + @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external firewall appliance.") + private Long podId; + @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the PXE server appliance.") private String url; @@ -68,6 +71,10 @@ public class AddPxeServerCmd extends BaseCmd { public String getType() { return type; } + + public Long getPod() { + return podId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java index 73db98ef369..c6199e211c1 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java @@ -37,18 +37,16 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements @Override public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { long zoneId = cmd.getZoneId(); + Long podId = cmd.getPod(); DataCenterVO zone = _dcDao.findById(zoneId); - String zoneName; if (zone == null) { throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); - } else { - zoneName = zone.getName(); - } + } - List pxeServers = _hostDao.listByTypeDataCenter(Host.Type.PxeServer, zoneId); + List pxeServers = _hostDao.listBy(Host.Type.PxeServer, null, podId, zoneId); if (pxeServers.size() != 0) { - throw new InvalidParameterValueException("Already had a PXE server in zone: " + zoneName); + throw new InvalidParameterValueException("Already had a PXE server in Pod: " + podId + " zone: " + zoneId); } URI uri; @@ -65,10 +63,12 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements String guid = getPxeServerGuid(Long.toString(zoneId), PxeServerType.LinMin.getName(), ipAddress); Map params = new HashMap(); params.put("zone", Long.toString(zoneId)); + params.put("pod", podId.toString()); params.put("ip", ipAddress); params.put("username", username); params.put("password", password); params.put("guid", guid); + params.put("pod", Long.toString(cmd.getPod())); ServerResource resource = null; try { diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java index 401ec2e04b4..f4222afa798 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java @@ -48,6 +48,7 @@ public class LinMinPxeServerResource implements ServerResource { String _password; String _ip; String _zoneId; + String _podId; class XmlReturn { NodeList nList; @@ -86,6 +87,7 @@ public class LinMinPxeServerResource implements ServerResource { _username = (String)params.get("username"); _password = (String)params.get("password"); _zoneId = (String)params.get("zone"); + _podId = (String)params.get("pod"); if (_guid == null) { throw new ConfigurationException("No Guid specified"); @@ -95,6 +97,10 @@ public class LinMinPxeServerResource implements ServerResource { throw new ConfigurationException("No Zone specified"); } + if (_podId == null) { + throw new ConfigurationException("No Pod specified"); + } + if (_ip == null) { throw new ConfigurationException("No IP specified"); } @@ -157,7 +163,7 @@ public class LinMinPxeServerResource implements ServerResource { StartupPxeServerCommand cmd = new StartupPxeServerCommand(); cmd.setName(_name); cmd.setDataCenter(_zoneId); - cmd.setPod(""); + cmd.setPod(_podId); cmd.setPrivateIpAddress(_ip); cmd.setStorageIpAddress(""); cmd.setVersion(""); diff --git a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java index 34521df33db..306c4070685 100644 --- a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java @@ -16,6 +16,7 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; import com.cloud.agent.manager.Commands; import com.cloud.api.commands.AttachVolumeCmd; @@ -271,7 +272,9 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet if (_itMgr.allocate(vm, template, offering, null, null, networks, null, plan, cmd.getHypervisor(), owner) == null) { return null; } - + + // startVirtualMachine() will retrieve this property + vm.setDetail("pxeboot", "true"); _vmDao.saveDetails(vm); if (s_logger.isDebugEnabled()) { @@ -374,16 +377,12 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet throw new PermissionDeniedException("The owner of " + vm + " either does not exist or is disabled: " + vm.getAccountId()); } - if (profile.getTemplate() == null) { + PxeServerType pxeType = (PxeServerType) profile.getParameter(Param.PxeSeverType); + if (pxeType == null) { s_logger.debug("This is a normal IPMI start, skip prepartion of PXE server"); return true; } - s_logger.debug("This is a PXE start, prepare PXE server first"); - PxeServerType pxeType = (PxeServerType) profile.getParameter(Param.PxeSeverType); - if (pxeType == null) { - throw new CloudRuntimeException("No PXE type specified"); - } PxeServerManager pxeMgr = null; ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); @@ -445,4 +444,14 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet return true; } + + @Override + public void finalizeStop(VirtualMachineProfile profile, StopAnswer answer) { + super.finalizeStop(profile, answer); + } + + @Override + public UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException { + return super.destroyVm(vmId); + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index eb038e3257d..e5737796f14 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2683,4 +2683,14 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager return _vmDao.search(sc, searchFilter); } + + @Override + public HypervisorType getHypervisorTypeOfUserVM(long vmid) { + UserVmVO userVm = _vmDao.findById(vmid); + if (userVm == null) { + throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmid); + } + + return userVm.getHypervisorType(); + } } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index a61d9411145..45c676da67b 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -841,8 +841,10 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } try { - _storageMgr.release(profile); - s_logger.debug("Successfully released storage resources for the vm " + vm); + if (vm.getHypervisorType() != HypervisorType.BareMetal) { + _storageMgr.release(profile); + s_logger.debug("Successfully released storage resources for the vm " + vm); + } } catch (Exception e) { s_logger.warn("Unable to release storage resources.", e); } diff --git a/utils/src/com/cloud/utils/script/Script.java b/utils/src/com/cloud/utils/script/Script.java index 614be735e1c..ea6fe12f250 100755 --- a/utils/src/com/cloud/utils/script/Script.java +++ b/utils/src/com/cloud/utils/script/Script.java @@ -154,6 +154,12 @@ public class Script implements Callable { return execute(new OutputInterpreter.OutputLogger(_logger)); } + @Override + public String toString() { + String[] command = _command.toArray(new String[_command.size()]); + return buildCommandLine(command); + } + public String execute(OutputInterpreter interpreter) { String[] command = _command.toArray(new String[_command.size()]); From ec7a6e6863297d6938fd2d170707a5551350b462 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 1 Mar 2011 14:55:22 -0800 Subject: [PATCH 08/11] Bug 8208 - bare metal provisioning Add LinMin username, password, apid fields in AddPxeServerCmd --- api/src/com/cloud/api/ApiConstants.java | 3 +++ server/src/com/cloud/api/AddPxeServerCmd.java | 21 +++++++++++++++ .../baremetal/LinMinPxeServerManagerImpl.java | 21 +++++++++++++++ .../baremetal/LinMinPxeServerResource.java | 27 ++++++++++++++----- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 02605c7a4bd..64ba091020b 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -195,6 +195,9 @@ public class ApiConstants { public static final String HOST_MEM_CAPACITY = "hostmemcapacity"; public static final String HOST_MAC = "hostmac"; public static final String PXE_SERVER_TYPE = "pxeservertype"; + public static final String LINMIN_USERNAME = "linminusername"; + public static final String LINMIN_PASSWORD = "linminpassword"; + public static final String LINMIN_APID = "linminapid"; } diff --git a/server/src/com/cloud/api/AddPxeServerCmd.java b/server/src/com/cloud/api/AddPxeServerCmd.java index f0ec9aefee6..941fa249585 100644 --- a/server/src/com/cloud/api/AddPxeServerCmd.java +++ b/server/src/com/cloud/api/AddPxeServerCmd.java @@ -47,6 +47,15 @@ public class AddPxeServerCmd extends BaseCmd { @Parameter(name=ApiConstants.PXE_SERVER_TYPE, type=CommandType.STRING, required = true, description="Type of PXE server. Current values are LinMin, DMCD") private String type; + + @Parameter(name=ApiConstants.LINMIN_USERNAME, type=CommandType.STRING, required = false, description="Optional, username uses to access LinMin API") + private String linminUsername; + + @Parameter(name=ApiConstants.LINMIN_PASSWORD, type=CommandType.STRING, required = false, description="Optional, password uses to access LinMin API") + private String linminPassword; + + @Parameter(name=ApiConstants.LINMIN_APID, type=CommandType.STRING, required = false, description="Optional, APID uses to access LinMin API") + private String linminApid; /////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -75,6 +84,18 @@ public class AddPxeServerCmd extends BaseCmd { public Long getPod() { return podId; } + + public String getLinMinUsername() { + return linminUsername; + } + + public String getLinMinPassword() { + return linminPassword; + } + + public String getLinMinApid() { + return linminApid; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java index c6199e211c1..b56a89e14ca 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java @@ -38,6 +38,9 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { long zoneId = cmd.getZoneId(); Long podId = cmd.getPod(); + String apiUsername; + String apiPassword; + String apid; DataCenterVO zone = _dcDao.findById(zoneId); if (zone == null) { @@ -57,6 +60,21 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements throw new InvalidParameterValueException(e.getMessage()); } + apiUsername = cmd.getLinMinUsername(); + apiPassword = cmd.getLinMinPassword(); + apid = cmd.getLinMinApid(); + if (apiUsername == null) { + throw new InvalidParameterValueException("No LinMin username specified, without it I can user LinMin API"); + } + + if (apiPassword == null) { + throw new InvalidParameterValueException("No LinMin password specified, without it I can user LinMin API"); + } + + if (apid == null) { + throw new InvalidParameterValueException("No LinMin apid specified, without it I can user LinMin API"); + } + String ipAddress = uri.getHost(); String username = cmd.getUsername(); String password = cmd.getPassword(); @@ -69,6 +87,9 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements params.put("password", password); params.put("guid", guid); params.put("pod", Long.toString(cmd.getPod())); + params.put("apiUsername", apiUsername); + params.put("apiPassword", apiPassword); + params.put("apid", apid); ServerResource resource = null; try { diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java index f4222afa798..f4e4a994b00 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java @@ -49,6 +49,9 @@ public class LinMinPxeServerResource implements ServerResource { String _ip; String _zoneId; String _podId; + String _apiUsername; + String _apiPassword; + String _apid; class XmlReturn { NodeList nList; @@ -88,6 +91,9 @@ public class LinMinPxeServerResource implements ServerResource { _password = (String)params.get("password"); _zoneId = (String)params.get("zone"); _podId = (String)params.get("pod"); + _apiUsername = (String)params.get("apiUsername"); + _apiPassword = (String)params.get("apiPassword"); + _apid = (String)params.get("apid"); if (_guid == null) { throw new ConfigurationException("No Guid specified"); @@ -113,6 +119,18 @@ public class LinMinPxeServerResource implements ServerResource { throw new ConfigurationException("No password specified"); } + if (_apiUsername == null) { + throw new ConfigurationException("No API username specified"); + } + + if (_apiPassword == null) { + throw new ConfigurationException("No API password specified"); + } + + if (_apid == null) { + throw new ConfigurationException("No A specified"); + } + com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22); s_logger.debug(String.format("Trying to connect to LinMin PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); @@ -212,19 +230,16 @@ public class LinMinPxeServerResource implements ServerResource { protected PrepareLinMinPxeServerAnswer execute(PrepareLinMinPxeServerCommand cmd) { - String apiUserName = "root"; - String apiPassword = "password"; - String apid = "2ad644fb479871a0f5543dd6d29fe9ed"; StringBuffer askApid = new StringBuffer(); askApid.append("http://"); askApid.append(_ip); askApid.append("/tftpboot/www/lbmp-API.php?actiontype=provision&apid="); - askApid.append(apid); + askApid.append(_apid); askApid.append("&auth_user="); - askApid.append(apiUserName); + askApid.append(_apiUsername); askApid.append("&auth_user_pw="); - askApid.append(apiPassword); + askApid.append(_apiPassword); askApid.append("&rtn_format=XML&action=authorize"); InputSource s = httpCall(askApid.toString()); if (s == null) { From 7fa053370ed2aee537abd80bce7068205a3656dc Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 1 Mar 2011 17:47:37 -0800 Subject: [PATCH 09/11] 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; + } } From 5517046a66d742f8cec5d5dc9375f23f5dd1c832 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 8 Mar 2011 10:05:58 -0800 Subject: [PATCH 10/11] Bug 8208 - bare metal provisioning throw exception when pxe server is not per pod --- server/src/com/cloud/agent/manager/AgentManagerImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index de6ad88d954..2270ff48a36 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -2624,8 +2624,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, if (p == null) { if (type != Host.Type.SecondaryStorage && type != Host.Type.ExternalFirewall - && type != Host.Type.ExternalLoadBalancer - && type != Host.Type.PxeServer) { + && type != Host.Type.ExternalLoadBalancer) { /* * s_logger.info("Unable to find the pod so we are creating one." From 20a7d95c06809838ca898eca7cd45e7984fb3211 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 8 Mar 2011 10:45:50 -0800 Subject: [PATCH 11/11] Bug 8208 - bare metal provisioning make an individual package and move to premium --- server/src/com/cloud/api/AddPxeServerCmd.java | 131 ----- .../cloud/api/response/PxeServerResponse.java | 18 - .../baremetal/LinMinPxeServerManager.java | 5 - .../baremetal/LinMinPxeServerManagerImpl.java | 142 ------ .../baremetal/LinMinPxeServerResource.java | 345 ------------- .../com/cloud/baremetal/PxeServerManager.java | 37 -- .../cloud/baremetal/PxeServerManagerImpl.java | 70 --- .../DefaultComponentLibrary.java | 3 +- .../src/com/cloud/vm/BareMetalVmManager.java | 5 - .../com/cloud/vm/BareMetalVmManagerImpl.java | 457 ------------------ .../src/com/cloud/vm/UserVmManagerImpl.java | 120 ++--- 11 files changed, 61 insertions(+), 1272 deletions(-) delete mode 100644 server/src/com/cloud/api/AddPxeServerCmd.java delete mode 100644 server/src/com/cloud/api/response/PxeServerResponse.java delete mode 100644 server/src/com/cloud/baremetal/LinMinPxeServerManager.java delete mode 100644 server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java delete mode 100644 server/src/com/cloud/baremetal/LinMinPxeServerResource.java delete mode 100644 server/src/com/cloud/baremetal/PxeServerManager.java delete mode 100644 server/src/com/cloud/baremetal/PxeServerManagerImpl.java delete mode 100644 server/src/com/cloud/vm/BareMetalVmManager.java delete mode 100644 server/src/com/cloud/vm/BareMetalVmManagerImpl.java diff --git a/server/src/com/cloud/api/AddPxeServerCmd.java b/server/src/com/cloud/api/AddPxeServerCmd.java deleted file mode 100644 index 941fa249585..00000000000 --- a/server/src/com/cloud/api/AddPxeServerCmd.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.cloud.api; - -import org.apache.log4j.Logger; - -import com.cloud.api.ApiConstants; -import com.cloud.api.BaseCmd; -import com.cloud.api.Implementation; -import com.cloud.api.Parameter; -import com.cloud.api.ServerApiException; -import com.cloud.api.response.PxeServerResponse; -import com.cloud.baremetal.LinMinPxeServerManager; -import com.cloud.baremetal.PxeServerManager; -import com.cloud.baremetal.PxeServerManager.PxeServerType; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.host.Host; -import com.cloud.server.ManagementService; -import com.cloud.utils.component.ComponentLocator; -import com.cloud.utils.exception.CloudRuntimeException; - -@Implementation(description="Adds a PXE server appliance", responseObject = PxeServerResponse.class) -public class AddPxeServerCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(AddPxeServerCmd.class.getName()); - private static final String s_name = "addpxeserverresponse"; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external firewall appliance.") - private Long zoneId; - - @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external firewall appliance.") - private Long podId; - - @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the PXE server appliance.") - private String url; - - @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Username of PXE server appliance.") - private String username; - - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Password of the PXE server appliance.") - private String password; - - @Parameter(name=ApiConstants.PXE_SERVER_TYPE, type=CommandType.STRING, required = true, description="Type of PXE server. Current values are LinMin, DMCD") - private String type; - - @Parameter(name=ApiConstants.LINMIN_USERNAME, type=CommandType.STRING, required = false, description="Optional, username uses to access LinMin API") - private String linminUsername; - - @Parameter(name=ApiConstants.LINMIN_PASSWORD, type=CommandType.STRING, required = false, description="Optional, password uses to access LinMin API") - private String linminPassword; - - @Parameter(name=ApiConstants.LINMIN_APID, type=CommandType.STRING, required = false, description="Optional, APID uses to access LinMin API") - private String linminApid; - - /////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public Long getZoneId() { - return zoneId; - } - - public String getUrl() { - return url; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public String getType() { - return type; - } - - public Long getPod() { - return podId; - } - - public String getLinMinUsername() { - return linminUsername; - } - - public String getLinMinPassword() { - return linminPassword; - } - - public String getLinMinApid() { - return linminApid; - } - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, - ResourceAllocationException { - try { - PxeServerManager pxeServerMgr; - ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); - if (getType().equalsIgnoreCase(PxeServerType.LinMin.getName())) { - pxeServerMgr = locator.getManager(LinMinPxeServerManager.class); - } else { - throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unsupport PXE server type " + getType()); - } - Host pxeServer = pxeServerMgr.addPxeServer(this); - PxeServerResponse response = pxeServerMgr.getApiResponse(pxeServer); - response.setObjectName("pxeserver"); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } catch (InvalidParameterValueException ipve) { - throw new ServerApiException(BaseCmd.PARAM_ERROR, ipve.getMessage()); - } catch (CloudRuntimeException cre) { - throw new ServerApiException(BaseCmd.INTERNAL_ERROR, cre.getMessage()); - } - } -} diff --git a/server/src/com/cloud/api/response/PxeServerResponse.java b/server/src/com/cloud/api/response/PxeServerResponse.java deleted file mode 100644 index f2f167dce45..00000000000 --- a/server/src/com/cloud/api/response/PxeServerResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.cloud.api.response; - -import com.cloud.api.ApiConstants; -import com.cloud.serializer.Param; -import com.google.gson.annotations.SerializedName; - -public class PxeServerResponse extends BaseResponse { - @SerializedName(ApiConstants.ID) @Param(description="the ID of the PXE server") - private Long id; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } -} diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManager.java b/server/src/com/cloud/baremetal/LinMinPxeServerManager.java deleted file mode 100644 index 745c89dc594..00000000000 --- a/server/src/com/cloud/baremetal/LinMinPxeServerManager.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.cloud.baremetal; - -public interface LinMinPxeServerManager extends PxeServerManager { - -} diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java deleted file mode 100644 index c8fe4bc0c96..00000000000 --- a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.cloud.baremetal; - -import java.net.URI; -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.AgentManager; -import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerAnswer; -import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; -import com.cloud.api.AddPxeServerCmd; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.resource.ServerResource; -import com.cloud.utils.component.Inject; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.NicProfile; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; - -@Local(value = {LinMinPxeServerManager.class}) -public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements LinMinPxeServerManager { - private static final org.apache.log4j.Logger s_logger = Logger.getLogger(LinMinPxeServerManagerImpl.class); - @Inject DataCenterDao _dcDao; - @Inject HostDao _hostDao; - @Inject AgentManager _agentMgr; - - @Override - public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { - long zoneId = cmd.getZoneId(); - Long podId = cmd.getPod(); - String apiUsername; - String apiPassword; - String apid; - - DataCenterVO zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); - } - - List pxeServers = _hostDao.listBy(Host.Type.PxeServer, null, podId, zoneId); - if (pxeServers.size() != 0) { - throw new InvalidParameterValueException("Already had a PXE server in Pod: " + podId + " zone: " + zoneId); - } - - URI uri; - try { - uri = new URI(cmd.getUrl()); - } catch (Exception e) { - s_logger.debug(e); - throw new InvalidParameterValueException(e.getMessage()); - } - - apiUsername = cmd.getLinMinUsername(); - apiPassword = cmd.getLinMinPassword(); - apid = cmd.getLinMinApid(); - if (apiUsername == null) { - 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 not use LinMin API"); - } - - if (apid == null) { - throw new InvalidParameterValueException("No LinMin apid specified, without it I can not use LinMin API"); - } - - String ipAddress = uri.getHost(); - String username = cmd.getUsername(); - String password = cmd.getPassword(); - String guid = getPxeServerGuid(Long.toString(zoneId), PxeServerType.LinMin.getName(), ipAddress); - Map params = new HashMap(); - params.put("zone", Long.toString(zoneId)); - params.put("pod", podId.toString()); - params.put("ip", ipAddress); - params.put("username", username); - params.put("password", password); - params.put("guid", guid); - params.put("pod", Long.toString(cmd.getPod())); - params.put("apiUsername", apiUsername); - params.put("apiPassword", apiPassword); - params.put("apid", apid); - - ServerResource resource = null; - try { - if (cmd.getType().equalsIgnoreCase(PxeServerType.LinMin.getName())) { - resource = new LinMinPxeServerResource(); - resource.configure("LinMin PXE resource", params); - } - } catch (Exception e) { - s_logger.debug(e); - throw new CloudRuntimeException(e.getMessage()); - } - - Host pxeServer = _agentMgr.addHost(zoneId, resource, Host.Type.PxeServer, params); - if (pxeServer == null) { - throw new CloudRuntimeException("Cannot add PXE server as a host"); - } - - return pxeServer; - } - - @Override - public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId) { - List nics = profile.getNics(); - if (nics.size() == 0) { - throw new CloudRuntimeException("Cannot do PXE start without nic"); - } - - NicProfile pxeNic = nics.get(0); - String mac = pxeNic.getMacAddress(); - String ip = pxeNic.getIp4Address(); - String gateway = pxeNic.getGateway(); - String mask = pxeNic.getNetmask(); - String dns = pxeNic.getDns1(); - if (dns == null) { - dns = pxeNic.getDns2(); - } - - try { - String linMinTpl = profile.getTemplate().getUrl(); - assert linMinTpl != null : "How can a null template get here!!!"; - PrepareLinMinPxeServerCommand cmd = new PrepareLinMinPxeServerCommand(ip, mac, mask, gateway, dns, linMinTpl, - profile.getVirtualMachine().getName(), dest.getHost().getName()); - PrepareLinMinPxeServerAnswer ans = (PrepareLinMinPxeServerAnswer) _agentMgr.send(pxeServerId, cmd); - return ans.getResult(); - } catch (Exception e) { - s_logger.warn("Cannot prepare PXE server", e); - return false; - } - } -} diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java deleted file mode 100644 index f4e4a994b00..00000000000 --- a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java +++ /dev/null @@ -1,345 +0,0 @@ -package com.cloud.baremetal; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.Map; - -import javax.naming.ConfigurationException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.apache.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -import com.cloud.agent.IAgentControl; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.PingCommand; -import com.cloud.agent.api.PingRoutingCommand; -import com.cloud.agent.api.ReadyAnswer; -import com.cloud.agent.api.ReadyCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupPxeServerCommand; -import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerAnswer; -import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.host.Host.Type; -import com.cloud.resource.ServerResource; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.ssh.SSHCmdHelper; -import com.cloud.vm.VirtualMachine.State; - -public class LinMinPxeServerResource implements ServerResource { - private static final Logger s_logger = Logger.getLogger(LinMinPxeServerResource.class); - String _name; - String _guid; - String _username; - String _password; - String _ip; - String _zoneId; - String _podId; - String _apiUsername; - String _apiPassword; - String _apid; - - class XmlReturn { - NodeList nList; - public XmlReturn(InputSource s, String tagName) { - try { - DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); - Document doc = dBuilder.parse(s); - doc.getDocumentElement().normalize(); - nList = doc.getElementsByTagName(tagName); - } catch (Exception e) { - s_logger.debug("The XML file:"); - s_logger.debug(s.toString()); - s_logger.debug("Cannot parse XMl file", e); - nList = null; - } - } - - public String getValue(String tag) { - if (nList == null || nList.getLength() == 0) { - throw new InvalidParameterValueException("invalid XML file"); - } - - Element e = (Element)nList.item(0); - NodeList nlList= e.getElementsByTagName(tag).item(0).getChildNodes(); - Node nValue = (Node)nlList.item(0); - return nValue.getNodeValue(); - } - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - _guid = (String)params.get("guid"); - _ip = (String)params.get("ip"); - _username = (String)params.get("username"); - _password = (String)params.get("password"); - _zoneId = (String)params.get("zone"); - _podId = (String)params.get("pod"); - _apiUsername = (String)params.get("apiUsername"); - _apiPassword = (String)params.get("apiPassword"); - _apid = (String)params.get("apid"); - - if (_guid == null) { - throw new ConfigurationException("No Guid specified"); - } - - if (_zoneId == null) { - throw new ConfigurationException("No Zone specified"); - } - - if (_podId == null) { - throw new ConfigurationException("No Pod specified"); - } - - if (_ip == null) { - throw new ConfigurationException("No IP specified"); - } - - if (_username == null) { - throw new ConfigurationException("No username specified"); - } - - if (_password == null) { - throw new ConfigurationException("No password specified"); - } - - if (_apiUsername == null) { - throw new ConfigurationException("No API username specified"); - } - - if (_apiPassword == null) { - throw new ConfigurationException("No API password specified"); - } - - if (_apid == null) { - throw new ConfigurationException("No A specified"); - } - - com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22); - - s_logger.debug(String.format("Trying to connect to LinMin PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password)); - try { - sshConnection.connect(null, 60000, 60000); - if (!sshConnection.authenticateWithPassword(_username, _password)) { - s_logger.debug("SSH Failed to authenticate"); - throw new ConfigurationException(String.format("Cannot connect to LinMin PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, - _password)); - } - - if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "[ -d '/home/tftpboot' ] && [ -d '/usr/local/linmin' ]")) { - throw new ConfigurationException("Cannot find LinMin directory /home/tftpboot, /usr/local/linmin on PXE server"); - } - - return true; - } catch (Exception e) { - throw new ConfigurationException(e.getMessage()); - } finally { - if (sshConnection != null) { - sshConnection.close(); - } - } - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } - - @Override - public String getName() { - return _name; - } - - @Override - public Type getType() { - return Type.PxeServer; - } - - @Override - public StartupCommand[] initialize() { - StartupPxeServerCommand cmd = new StartupPxeServerCommand(); - cmd.setName(_name); - cmd.setDataCenter(_zoneId); - cmd.setPod(_podId); - cmd.setPrivateIpAddress(_ip); - cmd.setStorageIpAddress(""); - cmd.setVersion(""); - cmd.setGuid(_guid); - return new StartupCommand[]{cmd}; - } - - @Override - public PingCommand getCurrentStatus(long id) { - //TODO: check server - return new PingRoutingCommand(getType(), id, new HashMap()); - } - - protected ReadyAnswer execute(ReadyCommand cmd) { - s_logger.debug("LinMin resource " + _name + " is ready"); - return new ReadyAnswer(cmd); - } - - private InputSource httpCall(String urlStr) { - try { - s_logger.debug("Execute http call " + urlStr); - URL url = new URL(urlStr); - URLConnection conn = url.openConnection(); - conn.setReadTimeout(30000); - BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); - StringBuffer xmlStuff = new StringBuffer(); - String line; - while ((line = in.readLine()) != null) { - xmlStuff.append(line); - } - StringReader statsReader = new StringReader(xmlStuff.toString()); - InputSource statsSource = new InputSource(statsReader); - s_logger.debug("Http call retrun:"); - s_logger.debug(xmlStuff.toString()); - return statsSource; - } catch (MalformedURLException e) { - throw new CloudRuntimeException("URL is malformed " + urlStr, e); - } catch (IOException e) { - s_logger.warn("can not do http call", e); - return null; - }catch (Exception e) { - s_logger.warn("Cannot do http call " + urlStr, e); - throw new CloudRuntimeException(e.getStackTrace().toString()); - } - } - - - protected PrepareLinMinPxeServerAnswer execute(PrepareLinMinPxeServerCommand cmd) { - StringBuffer askApid = new StringBuffer(); - - askApid.append("http://"); - askApid.append(_ip); - askApid.append("/tftpboot/www/lbmp-API.php?actiontype=provision&apid="); - askApid.append(_apid); - askApid.append("&auth_user="); - askApid.append(_apiUsername); - askApid.append("&auth_user_pw="); - askApid.append(_apiPassword); - askApid.append("&rtn_format=XML&action=authorize"); - InputSource s = httpCall(askApid.toString()); - if (s == null) { - return new PrepareLinMinPxeServerAnswer(cmd, "Http call failed"); - } - - try { - XmlReturn r = new XmlReturn(s, "LinMinBareMetalAPI"); - String res = r.getValue("actionResultsMsg"); - s_logger.debug(s.toString()); - if (!res.startsWith("Successful")) { - return new PrepareLinMinPxeServerAnswer(cmd, "Acquire APID failed"); - } - - String apid5 = r.getValue("apid"); - if (apid5 == null) { - return new PrepareLinMinPxeServerAnswer(cmd, "Cannot get 5 minutes APID " + apid5); - } - - StringBuffer addRole = new StringBuffer(); - addRole.append("http://"); - addRole.append(_ip); - addRole.append("/tftpboot/www/lbmp-API.php?actiontype=provision&user_supplied_id="); - addRole.append(cmd.getVmName()); - addRole.append("&mac_address="); - addRole.append(cmd.getMac().replaceAll(":", "%3A")); - addRole.append("&apid="); - addRole.append(apid5); - addRole.append("&control_file_template="); - addRole.append(cmd.getTemplate().replace(' ', '+')); - addRole.append("&node_name="); - addRole.append(cmd.getHostName()); - addRole.append("&node_domain="); - addRole.append(cmd.getHostName()); - addRole.append("&node_password=password"); - addRole.append("&node_time_zone=Etc%2FGMT-8"); - if (cmd.getIp() != null) { - addRole.append("&node_ip_address="); - addRole.append(cmd.getIp()); - } - if (cmd.getNetMask() != null) { - addRole.append("&node_subnet_mask="); - addRole.append(cmd.getNetMask()); - } - if (cmd.getDns() != null) { - addRole.append("&node_nameserver="); - addRole.append(cmd.getDns()); - } - if (cmd.getGateWay() != null) { - addRole.append("&node_default_gateway="); - addRole.append(cmd.getGateWay()); - } - addRole.append("&enable_provisioning_flag=nextbootonly&rtn_format=XML&action=add"); - - s = httpCall(addRole.toString()); - if (s == null) { - return new PrepareLinMinPxeServerAnswer(cmd, "Http call failed"); - } - r = new XmlReturn(s, "LinMinBareMetalAPI"); - res = r.getValue("actionResultsMsg"); - s_logger.debug(s.toString()); - if (!res.startsWith("Successful")) { - return new PrepareLinMinPxeServerAnswer(cmd, "Add LinMin role failed"); - } - } catch (Exception e) { - s_logger.warn("Cannot parse result from Lin Min server", e); - return new PrepareLinMinPxeServerAnswer(cmd, e.getMessage()); - } - - s_logger.debug("Prepare LinMin PXE server successfully"); - return new PrepareLinMinPxeServerAnswer(cmd); - } - - @Override - public Answer executeRequest(Command cmd) { - if (cmd instanceof ReadyCommand) { - return execute((ReadyCommand) cmd); - } else if (cmd instanceof PrepareLinMinPxeServerCommand) { - return execute((PrepareLinMinPxeServerCommand)cmd); - } else { - return Answer.createUnsupportedCommandAnswer(cmd); - } - } - - @Override - public void disconnected() { - // TODO Auto-generated method stub - - } - - @Override - public IAgentControl getAgentControl() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setAgentControl(IAgentControl agentControl) { - // TODO Auto-generated method stub - - } - -} diff --git a/server/src/com/cloud/baremetal/PxeServerManager.java b/server/src/com/cloud/baremetal/PxeServerManager.java deleted file mode 100644 index f1ac51aa1fb..00000000000 --- a/server/src/com/cloud/baremetal/PxeServerManager.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.cloud.baremetal; - -import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; -import com.cloud.api.AddPxeServerCmd; -import com.cloud.api.response.PxeServerResponse; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.host.Host; -import com.cloud.utils.component.Manager; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; - -public interface PxeServerManager extends Manager { - public static class PxeServerType { - private String _name; - - public static final PxeServerType LinMin = new PxeServerType("LinMin"); - public static final PxeServerType DMCD = new PxeServerType("DMCD"); - - public PxeServerType(String name) { - _name = name; - } - - public String getName() { - return _name; - } - - } - - public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException; - - public PxeServerResponse getApiResponse(Host pxeServer); - - public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId); -} diff --git a/server/src/com/cloud/baremetal/PxeServerManagerImpl.java b/server/src/com/cloud/baremetal/PxeServerManagerImpl.java deleted file mode 100644 index 77a20bf4dcd..00000000000 --- a/server/src/com/cloud/baremetal/PxeServerManagerImpl.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.cloud.baremetal; - -import java.util.Map; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; -import com.cloud.api.AddPxeServerCmd; -import com.cloud.api.response.PxeServerResponse; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.host.Host; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachineProfile; - -@Local(value = {PxeServerManager.class}) -public class PxeServerManagerImpl implements PxeServerManager { - private static final org.apache.log4j.Logger s_logger = Logger.getLogger(PxeServerManagerImpl.class); - protected String _name; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - return true; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } - - @Override - public String getName() { - return _name; - } - - protected String getPxeServerGuid(String zoneId, String name, String ip) { - return zoneId + "-" + name + "-" + ip; - } - - @Override - public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { - // TODO Auto-generated method stub - return null; - } - - @Override - public PxeServerResponse getApiResponse(Host pxeServer) { - PxeServerResponse response = new PxeServerResponse(); - response.setId(pxeServer.getId()); - return response; - } - - - @Override - public boolean prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context, Long pxeServerId) { - return true; - } - -} diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index 2d8ea99e074..d67306f69d0 100644 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -147,7 +147,6 @@ import com.cloud.vm.dao.SecondaryStorageVmDaoImpl; import com.cloud.vm.dao.UserVmDaoImpl; import com.cloud.vm.dao.UserVmDetailsDaoImpl; import com.cloud.vm.dao.VMInstanceDaoImpl; -import com.cloud.vm.BareMetalVmManagerImpl;; public class DefaultComponentLibrary implements ComponentLibrary { @@ -325,7 +324,7 @@ public class DefaultComponentLibrary implements ComponentLibrary { addManager("ClusteredAgentManager", ClusteredAgentManagerImpl.class); addManager("VirtualMachineManager", ClusteredVirtualMachineManagerImpl.class); addManager("HypervisorGuruManager", HypervisorGuruManagerImpl.class); - addManager("BareMetalVmManager", BareMetalVmManagerImpl.class); + ComponentInfo info = addManager("ConsoleProxyManager", ConsoleProxyManagerImpl.class); info.addParameter("consoleproxy.sslEnabled", "true"); diff --git a/server/src/com/cloud/vm/BareMetalVmManager.java b/server/src/com/cloud/vm/BareMetalVmManager.java deleted file mode 100644 index 9e952a4dccb..00000000000 --- a/server/src/com/cloud/vm/BareMetalVmManager.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.cloud.vm; - -public interface BareMetalVmManager extends UserVmManager { - -} diff --git a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java deleted file mode 100644 index 306c4070685..00000000000 --- a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java +++ /dev/null @@ -1,457 +0,0 @@ -package com.cloud.vm; - -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; -import com.cloud.agent.manager.Commands; -import com.cloud.api.commands.AttachVolumeCmd; -import com.cloud.api.commands.CreateTemplateCmd; -import com.cloud.api.commands.DeployVMCmd; -import com.cloud.api.commands.DetachVolumeCmd; -import com.cloud.api.commands.UpgradeVMCmd; -import com.cloud.baremetal.LinMinPxeServerManager; -import com.cloud.baremetal.PxeServerManager; -import com.cloud.baremetal.PxeServerManager.PxeServerType; -import com.cloud.configuration.ResourceCount.ResourceType; -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.deploy.DataCenterDeployment; -import com.cloud.deploy.DeployDestination; -import com.cloud.domain.DomainVO; -import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.exception.StorageUnavailableException; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.network.NetworkVO; -import com.cloud.network.IpAddrAllocator.IpAddr; -import com.cloud.network.Networks.TrafficType; -import com.cloud.server.ManagementService; -import com.cloud.service.ServiceOfferingVO; -import com.cloud.storage.Storage; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.Volume; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.user.Account; -import com.cloud.user.AccountVO; -import com.cloud.user.SSHKeyPair; -import com.cloud.user.UserContext; -import com.cloud.user.UserVO; -import com.cloud.uservm.UserVm; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.component.ComponentLocator; -import com.cloud.utils.component.Manager; -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.crypt.RSAHelper; -import com.cloud.utils.db.DB; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.net.NetUtils; -import com.cloud.vm.VirtualMachine.Type; -import com.cloud.vm.VirtualMachineProfile.Param; - -@Local(value={BareMetalVmManager.class, BareMetalVmService.class}) -public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMetalVmManager, BareMetalVmService, Manager { - private static final Logger s_logger = Logger.getLogger(BareMetalVmManagerImpl.class); - private ConfigurationDao _configDao; - - @Override - public boolean attachISOToVM(long vmId, long isoId, boolean attach) { - s_logger.warn("attachISOToVM is not supported by Bare Metal, just fake a true"); - return true; - } - - @Override - public Volume attachVolumeToVM(AttachVolumeCmd command) { - s_logger.warn("attachVolumeToVM is not supported by Bare Metal, return null"); - return null; - } - - @Override - public Volume detachVolumeFromVM(DetachVolumeCmd cmd) { - s_logger.warn("detachVolumeFromVM is not supported by Bare Metal, return null"); - return null; - } - - @Override - public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) { - s_logger.warn("upgradeVirtualMachine is not supported by Bare Metal, return null"); - return null; - } - - @Override - public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, ResourceAllocationException { - s_logger.warn("createPrivateTemplateRecord is not supported by Bare Metal, return null"); - return null; - } - - @Override @DB - public VMTemplateVO createPrivateTemplate(CreateTemplateCmd command) throws CloudRuntimeException { - s_logger.warn("createPrivateTemplate is not supported by Bare Metal, return null"); - return null; - } - - @Override - public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, - StorageUnavailableException, ResourceAllocationException { - Account caller = UserContext.current().getCaller(); - - String accountName = cmd.getAccountName(); - Long domainId = cmd.getDomainId(); - List networkList = cmd.getNetworkIds(); - String group = cmd.getGroup(); - - Account owner = _accountDao.findActiveAccount(accountName, domainId); - if (owner == null) { - throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId); - } - - _accountMgr.checkAccess(caller, owner); - long accountId = owner.getId(); - - DataCenterVO dc = _dcDao.findById(cmd.getZoneId()); - if (dc == null) { - throw new InvalidParameterValueException("Unable to find zone: " + cmd.getZoneId()); - } - - if (dc.getDomainId() != null) { - DomainVO domain = _domainDao.findById(dc.getDomainId()); - if (domain == null) { - throw new CloudRuntimeException("Unable to find the domain " + dc.getDomainId() + " for the zone: " + dc); - } - _accountMgr.checkAccess(caller, domain); - _accountMgr.checkAccess(owner, domain); - } - - // check if account/domain is with in resource limits to create a new vm - if (_accountMgr.resourceLimitExceeded(owner, ResourceType.user_vm)) { - ResourceAllocationException rae = new ResourceAllocationException("Maximum number of virtual machines for account: " + owner.getAccountName() - + " has been exceeded."); - rae.setResourceType("vm"); - throw rae; - } - - ServiceOfferingVO offering = _serviceOfferingDao.findById(cmd.getServiceOfferingId()); - if (offering == null || offering.getRemoved() != null) { - throw new InvalidParameterValueException("Unable to find service offering: " + cmd.getServiceOfferingId()); - } - - VMTemplateVO template = _templateDao.findById(cmd.getTemplateId()); - // Make sure a valid template ID was specified - if (template == null || template.getRemoved() != null) { - throw new InvalidParameterValueException("Unable to use template " + cmd.getTemplateId()); - } - - if (template.getTemplateType().equals(TemplateType.SYSTEM)) { - throw new InvalidParameterValueException("Unable to use system template " + cmd.getTemplateId()+" to deploy a user vm"); - } - - if (template.getFormat() != Storage.ImageFormat.BAREMETAL) { - throw new InvalidParameterValueException("Unable to use non Bare Metal template" + cmd.getTemplateId() +" to deploy a bare metal vm"); - } - - String userData = cmd.getUserData(); - byte [] decodedUserData = null; - if (userData != null) { - if (userData.length() >= 2 * MAX_USER_DATA_LENGTH_BYTES) { - throw new InvalidParameterValueException("User data is too long"); - } - decodedUserData = org.apache.commons.codec.binary.Base64.decodeBase64(userData.getBytes()); - if (decodedUserData.length > MAX_USER_DATA_LENGTH_BYTES){ - throw new InvalidParameterValueException("User data is too long"); - } - if (decodedUserData.length < 1) { - throw new InvalidParameterValueException("User data is too short"); - } - } - - // Find an SSH public key corresponding to the key pair name, if one is given - String sshPublicKey = null; - if (cmd.getSSHKeyPairName() != null && !cmd.getSSHKeyPairName().equals("")) { - Account account = UserContext.current().getCaller(); - SSHKeyPair pair = _sshKeyPairDao.findByName(account.getAccountId(), account.getDomainId(), cmd.getSSHKeyPairName()); - if (pair == null) { - throw new InvalidParameterValueException("A key pair with name '" + cmd.getSSHKeyPairName() + "' was not found."); - } - - sshPublicKey = pair.getPublicKey(); - } - - _accountMgr.checkAccess(caller, template); - - DataCenterDeployment plan = new DataCenterDeployment(dc.getId()); - - s_logger.debug("Allocating in the DB for bare metal vm"); - - if (dc.getNetworkType() != NetworkType.Basic || networkList != null) { - s_logger.warn("Bare Metal only supports basical network mode now, switch to baisc network automatically"); - } - - Network defaultNetwork = _networkMgr.getSystemNetworkByZoneAndTrafficType(dc.getId(), TrafficType.Guest); - if (defaultNetwork == null) { - throw new InvalidParameterValueException("Unable to find a default network to start a vm"); - } - - networkList = new ArrayList(); - networkList.add(defaultNetwork.getId()); - - List> networks = new ArrayList>(); - short defaultNetworkNumber = 0; - for (Long networkId : networkList) { - NetworkVO network = _networkDao.findById(networkId); - if (network == null) { - throw new InvalidParameterValueException("Unable to find network by id " + networkId); - } else { - if (!network.isShared()) { - //Check account permissions - List networkMap = _networkDao.listBy(accountId, networkId); - if (networkMap == null || networkMap.isEmpty()) { - throw new PermissionDeniedException("Unable to create a vm using network with id " + networkId + ", permission denied"); - } - } - - if (network.isDefault()) { - defaultNetworkNumber++; - } - networks.add(new Pair(network, null)); - } - } - - //at least one network default network has to be set - if (defaultNetworkNumber == 0) { - throw new InvalidParameterValueException("At least 1 default network has to be specified for the vm"); - } else if (defaultNetworkNumber >1) { - throw new InvalidParameterValueException("Only 1 default network per vm is supported"); - } - - long id = _vmDao.getNextInSequence(Long.class, "id"); - - String hostName = cmd.getName(); - String instanceName = VirtualMachineName.getVmName(id, owner.getId(), _instance); - if (hostName == null) { - hostName = instanceName; - } else { - //verify hostName (hostname doesn't have to be unique) - if (!NetUtils.verifyDomainNameLabel(hostName, true)) { - throw new InvalidParameterValueException("Invalid name. Vm name can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + - "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); - } - } - - UserVmVO vm = new UserVmVO(id, instanceName, cmd.getDisplayName(), template.getId(), HypervisorType.BareMetal, - template.getGuestOSId(), offering.getOfferHA(), domainId, owner.getId(), offering.getId(), userData, hostName); - - if (sshPublicKey != null) { - vm.setDetail("SSH.PublicKey", sshPublicKey); - } - - if (_itMgr.allocate(vm, template, offering, null, null, networks, null, plan, cmd.getHypervisor(), owner) == null) { - return null; - } - - // startVirtualMachine() will retrieve this property - vm.setDetail("pxeboot", "true"); - _vmDao.saveDetails(vm); - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Successfully allocated DB entry for " + vm); - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Successfully allocated DB entry for " + vm); - } - UserContext.current().setEventDetails("Vm Id: " + vm.getId()); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, accountId, dc.getId(), vm.getId(), vm.getName(), offering.getId(), - template.getId(), null); - _usageEventDao.persist(usageEvent); - - _accountMgr.incrementResourceCount(accountId, ResourceType.user_vm); - - // Assign instance to the group - try { - if (group != null) { - boolean addToGroup = addInstanceToGroup(Long.valueOf(id), group); - if (!addToGroup) { - throw new CloudRuntimeException("Unable to assign Vm to the group " + group); - } - } - } catch (Exception ex) { - throw new CloudRuntimeException("Unable to assign Vm to the group " + group); - } - - return vm; - } - - public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { - long vmId = cmd.getEntityId(); - UserVmVO vm = _vmDao.findById(vmId); - _vmDao.loadDetails(vm); - - List servers = _hostDao.listBy(Host.Type.PxeServer, vm.getDataCenterId()); - if (servers.size() == 0) { - throw new CloudRuntimeException("Cannot find PXE server, please make sure there is one PXE server per zone"); - } - HostVO pxeServer = servers.get(0); - - VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); - if (template == null || template.getFormat() != Storage.ImageFormat.BAREMETAL) { - throw new InvalidParameterValueException("Invalid template with id = " + vm.getTemplateId()); - } - - Map params = new HashMap(); - //TODO: have to ugly harding code here - if (pxeServer.getResource().equalsIgnoreCase("com.cloud.baremetal.LinMinPxeServerResource")) { - params.put(Param.PxeSeverType, PxeServerType.LinMin); - } else { - throw new CloudRuntimeException("Unkown PXE server resource " + pxeServer.getResource()); - } - - return startVirtualMachine(cmd, params); - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - - ComponentLocator locator = ComponentLocator.getCurrentLocator(); - _configDao = locator.getDao(ConfigurationDao.class); - if (_configDao == null) { - throw new ConfigurationException("Unable to get the configuration dao."); - } - - Map configs = _configDao.getConfiguration("AgentManager", params); - - _instance = configs.get("instance.name"); - if (_instance == null) { - _instance = "DEFAULT"; - } - - String workers = configs.get("expunge.workers"); - int wrks = NumbersUtil.parseInt(workers, 10); - - String time = configs.get("expunge.interval"); - _expungeInterval = NumbersUtil.parseInt(time, 86400); - - time = configs.get("expunge.delay"); - _expungeDelay = NumbersUtil.parseInt(time, _expungeInterval); - - _executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger")); - - _itMgr.registerGuru(Type.UserBareMetal, this); - - s_logger.info("User VM Manager is configured."); - - return true; - } - - @Override - public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - UserVmVO vm = profile.getVirtualMachine(); - Account owner = _accountDao.findById(vm.getAccountId()); - - if (owner == null || owner.getState() == Account.State.disabled) { - throw new PermissionDeniedException("The owner of " + vm + " either does not exist or is disabled: " + vm.getAccountId()); - } - - PxeServerType pxeType = (PxeServerType) profile.getParameter(Param.PxeSeverType); - if (pxeType == null) { - s_logger.debug("This is a normal IPMI start, skip prepartion of PXE server"); - return true; - } - s_logger.debug("This is a PXE start, prepare PXE server first"); - - PxeServerManager pxeMgr = null; - ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); - if (pxeType == PxeServerType.LinMin) { - pxeMgr = locator.getManager(LinMinPxeServerManager.class); - } else { - throw new CloudRuntimeException("Unsupport PXE type " + pxeType.toString()); - } - - if (pxeMgr == null) { - throw new CloudRuntimeException("No PXE manager find for type " + pxeType.toString()); - } - - List servers = _hostDao.listBy(Host.Type.PxeServer, vm.getDataCenterId()); - if (servers.size() == 0) { - throw new CloudRuntimeException("Cannot find PXE server, please make sure there is one PXE server per zone"); - } - HostVO pxeServer = servers.get(0); - - if (!pxeMgr.prepare(profile, dest, context, pxeServer.getId())) { - throw new CloudRuntimeException("Pepare PXE server failed"); - } - - profile.addBootArgs("PxeBoot"); - - return true; - } - - @Override - public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - UserVmVO userVm = profile.getVirtualMachine(); - List nics = _nicDao.listByVmId(userVm.getId()); - for (NicVO nic : nics) { - NetworkVO network = _networkDao.findById(nic.getNetworkId()); - if (network.getTrafficType() == TrafficType.Guest) { - userVm.setPrivateIpAddress(nic.getIp4Address()); - userVm.setPrivateMacAddress(nic.getMacAddress()); - } - } - _vmDao.update(userVm.getId(), userVm); - return true; - } - - @Override - public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) { - UserVmVO vm = profile.getVirtualMachine(); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_START, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), - vm.getServiceOfferingId(), vm.getTemplateId(), null); - _usageEventDao.persist(usageEvent); - - List nics = _nicDao.listByVmId(vm.getId()); - for (NicVO nic : nics) { - NetworkVO network = _networkDao.findById(nic.getNetworkId()); - long isDefault = (nic.isDefaultNic()) ? 1 : 0; - usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_CREATE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), - network.getNetworkOfferingId(), null, isDefault); - _usageEventDao.persist(usageEvent); - } - - return true; - } - - @Override - public void finalizeStop(VirtualMachineProfile profile, StopAnswer answer) { - super.finalizeStop(profile, answer); - } - - @Override - public UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException { - return super.destroyVm(vmId); - } -} diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index e5737796f14..60c6ac6ea88 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -197,68 +197,68 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class); private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 seconds - @Inject HostDao _hostDao = null; - @Inject DetailsDao _detailsDao = null; - @Inject DomainRouterDao _routerDao = null; - @Inject ServiceOfferingDao _offeringDao = null; - @Inject DiskOfferingDao _diskOfferingDao = null; - @Inject UserStatisticsDao _userStatsDao = null; - @Inject VMTemplateDao _templateDao = null; - @Inject VMTemplateHostDao _templateHostDao = null; - @Inject DomainDao _domainDao = null; - @Inject ResourceLimitDao _limitDao = null; - @Inject UserVmDao _vmDao = null; - @Inject VolumeDao _volsDao = null; - @Inject DataCenterDao _dcDao = null; - @Inject FirewallRulesDao _rulesDao = null; - @Inject LoadBalancerVMMapDao _loadBalancerVMMapDao = null; - @Inject LoadBalancerDao _loadBalancerDao = null; - @Inject IPAddressDao _ipAddressDao = null; - @Inject HostPodDao _podDao = null; - @Inject CapacityDao _capacityDao = null; - @Inject NetworkManager _networkMgr = null; - @Inject StorageManager _storageMgr = null; - @Inject SnapshotManager _snapshotMgr = null; - @Inject AgentManager _agentMgr = null; - @Inject ConfigurationManager _configMgr = null; - @Inject AccountDao _accountDao = null; - @Inject UserDao _userDao = null; - @Inject SnapshotDao _snapshotDao = null; - @Inject GuestOSDao _guestOSDao = null; - @Inject GuestOSCategoryDao _guestOSCategoryDao = null; - @Inject HighAvailabilityManager _haMgr = null; - @Inject AlertManager _alertMgr = null; - @Inject AccountManager _accountMgr; - @Inject AccountService _accountService; - @Inject AsyncJobManager _asyncMgr; - @Inject VlanDao _vlanDao; - @Inject ClusterDao _clusterDao; - @Inject AccountVlanMapDao _accountVlanMapDao; - @Inject StoragePoolDao _storagePoolDao; - @Inject VMTemplateHostDao _vmTemplateHostDao; - @Inject SecurityGroupManager _networkGroupMgr; - @Inject ServiceOfferingDao _serviceOfferingDao; - @Inject NetworkOfferingDao _networkOfferingDao; - @Inject EventDao _eventDao = null; - @Inject InstanceGroupDao _vmGroupDao; - @Inject InstanceGroupVMMapDao _groupVMMapDao; - @Inject VirtualMachineManager _itMgr; - @Inject NetworkDao _networkDao; - @Inject VirtualNetworkApplianceManager _routerMgr; - @Inject NicDao _nicDao; - @Inject RulesManager _rulesMgr; - @Inject LoadBalancingRulesManager _lbMgr; - @Inject UsageEventDao _usageEventDao; - @Inject SSHKeyPairDao _sshKeyPairDao; - @Inject UserVmDetailsDao _vmDetailsDao; + @Inject protected HostDao _hostDao = null; + @Inject protected DetailsDao _detailsDao = null; + @Inject protected DomainRouterDao _routerDao = null; + @Inject protected ServiceOfferingDao _offeringDao = null; + @Inject protected DiskOfferingDao _diskOfferingDao = null; + @Inject protected UserStatisticsDao _userStatsDao = null; + @Inject protected VMTemplateDao _templateDao = null; + @Inject protected VMTemplateHostDao _templateHostDao = null; + @Inject protected DomainDao _domainDao = null; + @Inject protected ResourceLimitDao _limitDao = null; + @Inject protected UserVmDao _vmDao = null; + @Inject protected VolumeDao _volsDao = null; + @Inject protected DataCenterDao _dcDao = null; + @Inject protected FirewallRulesDao _rulesDao = null; + @Inject protected LoadBalancerVMMapDao _loadBalancerVMMapDao = null; + @Inject protected LoadBalancerDao _loadBalancerDao = null; + @Inject protected IPAddressDao _ipAddressDao = null; + @Inject protected HostPodDao _podDao = null; + @Inject protected CapacityDao _capacityDao = null; + @Inject protected NetworkManager _networkMgr = null; + @Inject protected StorageManager _storageMgr = null; + @Inject protected SnapshotManager _snapshotMgr = null; + @Inject protected AgentManager _agentMgr = null; + @Inject protected ConfigurationManager _configMgr = null; + @Inject protected AccountDao _accountDao = null; + @Inject protected UserDao _userDao = null; + @Inject protected SnapshotDao _snapshotDao = null; + @Inject protected GuestOSDao _guestOSDao = null; + @Inject protected GuestOSCategoryDao _guestOSCategoryDao = null; + @Inject protected HighAvailabilityManager _haMgr = null; + @Inject protected AlertManager _alertMgr = null; + @Inject protected AccountManager _accountMgr; + @Inject protected AccountService _accountService; + @Inject protected AsyncJobManager _asyncMgr; + @Inject protected VlanDao _vlanDao; + @Inject protected ClusterDao _clusterDao; + @Inject protected AccountVlanMapDao _accountVlanMapDao; + @Inject protected StoragePoolDao _storagePoolDao; + @Inject protected VMTemplateHostDao _vmTemplateHostDao; + @Inject protected SecurityGroupManager _networkGroupMgr; + @Inject protected ServiceOfferingDao _serviceOfferingDao; + @Inject protected NetworkOfferingDao _networkOfferingDao; + @Inject protected EventDao _eventDao = null; + @Inject protected InstanceGroupDao _vmGroupDao; + @Inject protected InstanceGroupVMMapDao _groupVMMapDao; + @Inject protected VirtualMachineManager _itMgr; + @Inject protected NetworkDao _networkDao; + @Inject protected VirtualNetworkApplianceManager _routerMgr; + @Inject protected NicDao _nicDao; + @Inject protected RulesManager _rulesMgr; + @Inject protected LoadBalancingRulesManager _lbMgr; + @Inject protected UsageEventDao _usageEventDao; + @Inject protected SSHKeyPairDao _sshKeyPairDao; + @Inject protected UserVmDetailsDao _vmDetailsDao; - ScheduledExecutorService _executor = null; - int _expungeInterval; - int _expungeDelay; + protected ScheduledExecutorService _executor = null; + protected int _expungeInterval; + protected int _expungeDelay; - String _name; - String _instance; - String _zone; + protected String _name; + protected String _instance; + protected String _zone; private ConfigurationDao _configDao;